summaryrefslogtreecommitdiffstats
path: root/eval
diff options
context:
space:
mode:
authorArne Juul <arnej@yahoo-inc.com>2019-06-27 08:48:33 +0000
committerArne Juul <arnej@yahoo-inc.com>2019-07-04 11:49:32 +0000
commit5a993bc1a9272281e41ca220ee117d0f8d3081d8 (patch)
treef466bc6ec9e203a12973cfcb66cef49171f0fb75 /eval
parenteb95248e0f4e89e59e8af64efdcfc0388529b832 (diff)
add TypedCells and related functionality
* templated DenseTensor * templated DenseTensorModify * add templated TypedDenseTensorBuilder * remove DirectDenseTensorBuilder * remove unused TensorMapper * add dispatch structs * add unit test for generic dense join * add special handling of reducing all dimensions
Diffstat (limited to 'eval')
-rw-r--r--eval/CMakeLists.txt2
-rw-r--r--eval/src/tests/tensor/dense_generic_join/CMakeLists.txt8
-rw-r--r--eval/src/tests/tensor/dense_generic_join/dense_generic_join_test.cpp127
-rw-r--r--eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp8
-rw-r--r--eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp61
-rw-r--r--eval/src/tests/tensor/tensor_mapper/.gitignore1
-rw-r--r--eval/src/tests/tensor/tensor_mapper/CMakeLists.txt8
-rw-r--r--eval/src/tests/tensor/tensor_mapper/tensor_mapper_test.cpp199
-rw-r--r--eval/src/vespa/eval/eval/value_type.h9
-rw-r--r--eval/src/vespa/eval/tensor/CMakeLists.txt1
-rw-r--r--eval/src/vespa/eval/tensor/default_tensor_engine.cpp47
-rw-r--r--eval/src/vespa/eval/tensor/dense/CMakeLists.txt3
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_dot_product_function.cpp13
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp1
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_inplace_join_function.cpp7
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_inplace_map_function.cpp3
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp5
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor.cpp69
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor.h16
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp2
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h2
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_apply.h2
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_apply.hpp39
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp2
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h11
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp25
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h8
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp6
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp72
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp138
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_view.h11
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_xw_product_function.cpp13
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_xw_product_function.h2
-rw-r--r--eval/src/vespa/eval/tensor/dense/direct_dense_tensor_builder.cpp39
-rw-r--r--eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp4
-rw-r--r--eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h4
-rw-r--r--eval/src/vespa/eval/tensor/dense/typed_cells.cpp7
-rw-r--r--eval/src/vespa/eval/tensor/dense/typed_cells.h96
-rw-r--r--eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp45
-rw-r--r--eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h (renamed from eval/src/vespa/eval/tensor/dense/direct_dense_tensor_builder.h)18
-rw-r--r--eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp24
-rw-r--r--eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp34
-rw-r--r--eval/src/vespa/eval/tensor/serialization/dense_binary_format.h3
-rw-r--r--eval/src/vespa/eval/tensor/tensor_mapper.cpp274
-rw-r--r--eval/src/vespa/eval/tensor/tensor_mapper.h44
45 files changed, 692 insertions, 821 deletions
diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt
index e0159febdfe..d91e35f2d63 100644
--- a/eval/CMakeLists.txt
+++ b/eval/CMakeLists.txt
@@ -29,6 +29,7 @@ vespa_define_module(
src/tests/tensor/dense_add_dimension_optimizer
src/tests/tensor/dense_dot_product_function
src/tests/tensor/dense_fast_rename_optimizer
+ src/tests/tensor/dense_generic_join
src/tests/tensor/dense_inplace_join_function
src/tests/tensor/dense_inplace_map_function
src/tests/tensor/dense_remove_dimension_optimizer
@@ -39,7 +40,6 @@ vespa_define_module(
src/tests/tensor/tensor_add_operation
src/tests/tensor/tensor_address
src/tests/tensor/tensor_conformance
- src/tests/tensor/tensor_mapper
src/tests/tensor/tensor_modify_operation
src/tests/tensor/tensor_remove_operation
src/tests/tensor/tensor_serialization
diff --git a/eval/src/tests/tensor/dense_generic_join/CMakeLists.txt b/eval/src/tests/tensor/dense_generic_join/CMakeLists.txt
new file mode 100644
index 00000000000..1fbb35cb2b8
--- /dev/null
+++ b/eval/src/tests/tensor/dense_generic_join/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(eval_dense_generic_join_test_app TEST
+ SOURCES
+ dense_generic_join_test.cpp
+ DEPENDS
+ vespaeval
+)
+vespa_add_test(NAME eval_dense_generic_join_test_app COMMAND eval_dense_generic_join_test_app)
diff --git a/eval/src/tests/tensor/dense_generic_join/dense_generic_join_test.cpp b/eval/src/tests/tensor/dense_generic_join/dense_generic_join_test.cpp
new file mode 100644
index 00000000000..395437e13dd
--- /dev/null
+++ b/eval/src/tests/tensor/dense_generic_join/dense_generic_join_test.cpp
@@ -0,0 +1,127 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/eval/eval/tensor_function.h>
+#include <vespa/eval/eval/simple_tensor.h>
+#include <vespa/eval/eval/simple_tensor_engine.h>
+#include <vespa/eval/tensor/default_tensor_engine.h>
+#include <vespa/eval/tensor/dense/typed_dense_tensor_builder.h>
+#include <vespa/eval/tensor/dense/dense_tensor.h>
+#include <vespa/eval/eval/test/tensor_model.hpp>
+#include <vespa/eval/eval/test/eval_fixture.h>
+
+#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/vespalib/util/stash.h>
+
+using namespace vespalib;
+using namespace vespalib::eval;
+using namespace vespalib::eval::test;
+using namespace vespalib::tensor;
+using namespace vespalib::eval::tensor_function;
+
+const TensorEngine &prod_engine = DefaultTensorEngine::ref();
+
+double seq_value = 0.0;
+
+struct GlobalSequence : public Sequence {
+ GlobalSequence() {}
+ double operator[](size_t) const override {
+ seq_value += 1.0;
+ return seq_value;
+ }
+ ~GlobalSequence() {}
+};
+GlobalSequence seq;
+
+EvalFixture::ParamRepo make_params() {
+ return EvalFixture::ParamRepo()
+ .add("con_x5_A", spec({x(5) }, seq))
+ .add("con_x5y3_B", spec({x(5),y(3) }, seq))
+ .add("con_x5z4_C", spec({x(5), z(4)}, seq))
+ .add("con_x5y3z4_D", spec({x(5),y(3),z(4)}, seq))
+ .add("con_y3_E", spec({ y(3) }, seq))
+ .add("con_y3z4_F", spec({ y(3),z(4)}, seq))
+ .add("con_z4_G", spec({ z(4)}, seq))
+ .add("con_x5f_H", spec({x(5) }, seq), "tensor<float>(x[5])")
+ .add("con_x5y3_I", spec({x(5),y(3) }, seq), "tensor<float>(x[5],y[3])")
+ .add("con_x5z4_J", spec({x(5), z(4)}, seq), "tensor<float>(x[5],z[4])")
+ .add("con_x5y3z4_K", spec({x(5),y(3),z(4)}, seq), "tensor<float>(x[5],y[3],z[4])")
+ .add("con_y3_L", spec({ y(3) }, seq), "tensor<float>(y[3])")
+ .add("con_y3z4_M", spec({ y(3),z(4)}, seq), "tensor<float>(y[3],z[4])))")
+ .add("con_z4_N", spec({ z(4)}, seq), "tensor<float>(z[4]))")
+ .add("con_y2", spec({y(5)}, seq))
+ .add("con_y2f", spec({y(5)}, seq), "tensor<float>(y[2]))");
+}
+EvalFixture::ParamRepo param_repo = make_params();
+
+void verify_equal(const vespalib::string &expr) {
+ EvalFixture fixture(prod_engine, expr, param_repo, true, true);
+ EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
+}
+
+
+TEST("require that non-overlapping dense join works") {
+ TEST_DO(verify_equal("con_x5_A-con_y3_E"));
+ TEST_DO(verify_equal("con_x5_A+con_y3_E"));
+ TEST_DO(verify_equal("con_x5_A*con_y3_E"));
+
+ TEST_DO(verify_equal("con_x5_A-con_y3z4_F"));
+ TEST_DO(verify_equal("con_x5_A+con_y3z4_F"));
+ TEST_DO(verify_equal("con_x5_A*con_y3z4_F"));
+
+ TEST_DO(verify_equal("con_x5_A-con_z4_G"));
+ TEST_DO(verify_equal("con_x5_A+con_z4_G"));
+ TEST_DO(verify_equal("con_x5_A*con_z4_G"));
+
+ TEST_DO(verify_equal("con_x5y3_B-con_z4_G"));
+ TEST_DO(verify_equal("con_x5y3_B+con_z4_G"));
+ TEST_DO(verify_equal("con_x5y3_B*con_z4_G"));
+
+ TEST_DO(verify_equal("con_y3_E-con_z4_G"));
+ TEST_DO(verify_equal("con_y3_E+con_z4_G"));
+ TEST_DO(verify_equal("con_y3_E*con_z4_G"));
+}
+
+TEST("require that overlapping dense join works") {
+ TEST_DO(verify_equal("con_x5_A-con_x5y3_B"));
+ TEST_DO(verify_equal("con_x5_A+con_x5y3_B"));
+ TEST_DO(verify_equal("con_x5_A*con_x5y3_B"));
+
+ TEST_DO(verify_equal("con_x5_A-con_x5z4_C"));
+ TEST_DO(verify_equal("con_x5_A+con_x5z4_C"));
+ TEST_DO(verify_equal("con_x5_A*con_x5z4_C"));
+
+ TEST_DO(verify_equal("con_x5y3_B-con_y3_E"));
+ TEST_DO(verify_equal("con_x5y3_B+con_y3_E"));
+ TEST_DO(verify_equal("con_x5y3_B*con_y3_E"));
+
+ TEST_DO(verify_equal("con_x5y3_B-con_y3z4_F"));
+ TEST_DO(verify_equal("con_x5y3_B+con_y3z4_F"));
+ TEST_DO(verify_equal("con_x5y3_B*con_y3z4_F"));
+
+ TEST_DO(verify_equal("con_x5y3z4_D-con_x5y3_B"));
+ TEST_DO(verify_equal("con_x5y3z4_D+con_x5y3_B"));
+ TEST_DO(verify_equal("con_x5y3z4_D*con_x5y3_B"));
+
+ TEST_DO(verify_equal("con_x5y3z4_D-con_x5z4_C"));
+ TEST_DO(verify_equal("con_x5y3z4_D+con_x5z4_C"));
+ TEST_DO(verify_equal("con_x5y3z4_D*con_x5z4_C"));
+
+ TEST_DO(verify_equal("con_x5y3z4_D-con_y3z4_F"));
+ TEST_DO(verify_equal("con_x5y3z4_D+con_y3z4_F"));
+ TEST_DO(verify_equal("con_x5y3z4_D*con_y3z4_F"));
+
+ TEST_DO(verify_equal("con_x5y3z4_D-con_y3z4_F"));
+ TEST_DO(verify_equal("con_x5y3z4_D+con_y3z4_F"));
+ TEST_DO(verify_equal("con_x5y3z4_D*con_y3z4_F"));
+
+ TEST_DO(verify_equal("con_y3_E-con_y3z4_F"));
+ TEST_DO(verify_equal("con_y3_E+con_y3z4_F"));
+ TEST_DO(verify_equal("con_y3_E*con_y3z4_F"));
+
+ TEST_DO(verify_equal("con_y3z4_F-con_z4_G"));
+ TEST_DO(verify_equal("con_y3z4_F+con_z4_G"));
+ TEST_DO(verify_equal("con_y3z4_F*con_z4_G"));
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp b/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp
index 7e6b933d7c6..0533b1c92b7 100644
--- a/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp
+++ b/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp
@@ -13,11 +13,9 @@ using namespace vespalib::eval;
using namespace vespalib::tensor;
using namespace vespalib;
-using CellsRef = DenseTensorView::CellsRef;
-
const TensorEngine &engine = DefaultTensorEngine::ref();
-CellsRef getCellsRef(const eval::Value &value) {
+TypedCells getCellsRef(const eval::Value &value) {
return static_cast<const DenseTensorView &>(value).cellsRef();
}
@@ -58,8 +56,8 @@ TEST_F("require that DenseReplaceTypeFunction works as expected", Fixture()) {
f1.mock_child.is_mutable = false;
EXPECT_EQUAL(f1.my_fun.result_is_mutable(), false);
EXPECT_EQUAL(&f1.children[0].get().get(), &f1.mock_child);
- EXPECT_EQUAL(getCellsRef(f1.state.stack[0]).begin(), getCellsRef(*f1.my_value).begin());
- EXPECT_EQUAL(getCellsRef(f1.state.stack[0]).end(), getCellsRef(*f1.my_value).end());
+ EXPECT_EQUAL(getCellsRef(f1.state.stack[0]).data, getCellsRef(*f1.my_value).data);
+ EXPECT_EQUAL(getCellsRef(f1.state.stack[0]).size, getCellsRef(*f1.my_value).size);
EXPECT_EQUAL(f1.state.stack[0].get().type(), f1.new_type);
fprintf(stderr, "%s\n", f1.my_fun.as_string().c_str());
}
diff --git a/eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp b/eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp
index a0b7b60e2da..3f4641ed2ee 100644
--- a/eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp
+++ b/eval/src/tests/tensor/direct_dense_tensor_builder/direct_dense_tensor_builder_test.cpp
@@ -2,31 +2,36 @@
#include <vespa/vespalib/test/insertion_operators.h>
#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/eval/tensor/dense/direct_dense_tensor_builder.h>
+#include <vespa/eval/tensor/dense/typed_dense_tensor_builder.h>
#include <vespa/vespalib/util/exceptions.h>
using namespace vespalib::tensor;
using vespalib::IllegalArgumentException;
-using Builder = DirectDenseTensorBuilder;
+using BuilderDbl = TypedDenseTensorBuilder<double>;
+using BuilderFlt = TypedDenseTensorBuilder<float>;
using vespalib::eval::TensorSpec;
using vespalib::eval::ValueType;
using vespalib::ConstArrayRef;
-template <typename T> std::vector<T> make_vector(const ConstArrayRef<T> &ref) {
- std::vector<T> vec;
- for (const T &t: ref) {
- vec.push_back(t);
+struct CallMakeVector {
+ template <typename T>
+ static std::vector<double> call(const ConstArrayRef<T> &ref) {
+ std::vector<double> result;
+ result.reserve(ref.size());
+ for (T v : ref) {
+ result.push_back(v);
+ }
+ return result;
}
- return vec;
-}
+};
void assertTensor(const vespalib::string &type_spec,
- const DenseTensor::Cells &expCells,
+ const std::vector<double> &expCells,
const Tensor &tensor)
{
- const DenseTensor &realTensor = dynamic_cast<const DenseTensor &>(tensor);
+ const DenseTensorView &realTensor = dynamic_cast<const DenseTensorView &>(tensor);
EXPECT_EQUAL(ValueType::from_spec(type_spec), realTensor.type());
- EXPECT_EQUAL(expCells, make_vector(realTensor.cellsRef()));
+ EXPECT_EQUAL(expCells, dispatch_1<CallMakeVector>(realTensor.cellsRef()));
}
void assertTensorSpec(const TensorSpec &expSpec, const Tensor &tensor) {
@@ -35,7 +40,7 @@ void assertTensorSpec(const TensorSpec &expSpec, const Tensor &tensor) {
}
Tensor::UP build1DTensor() {
- Builder builder(ValueType::from_spec("tensor(x[3])"));
+ BuilderDbl builder(ValueType::from_spec("tensor(x[3])"));
builder.insertCell(0, 10);
builder.insertCell(1, 11);
builder.insertCell(2, 12);
@@ -55,7 +60,7 @@ TEST("require that 1d tensor can be converted to tensor spec") {
}
Tensor::UP build2DTensor() {
- Builder builder(ValueType::from_spec("tensor(x[3],y[2])"));
+ BuilderDbl builder(ValueType::from_spec("tensor(x[3],y[2])"));
builder.insertCell({0, 0}, 10);
builder.insertCell({0, 1}, 11);
builder.insertCell({1, 0}, 12);
@@ -81,7 +86,7 @@ TEST("require that 2d tensor can be converted to tensor spec") {
}
TEST("require that 3d tensor can be constructed") {
- Builder builder(ValueType::from_spec("tensor(x[3],y[2],z[2])"));
+ BuilderDbl builder(ValueType::from_spec("tensor(x[3],y[2],z[2])"));
builder.insertCell({0, 0, 0}, 10);
builder.insertCell({0, 0, 1}, 11);
builder.insertCell({0, 1, 0}, 12);
@@ -99,16 +104,26 @@ TEST("require that 3d tensor can be constructed") {
*builder.build());
}
+TEST("require that 2d tensor with float cells can be constructed") {
+ BuilderFlt builder(ValueType::from_spec("tensor<float>(x[3],y[2])"));
+ builder.insertCell({0, 1}, 2.5);
+ builder.insertCell({1, 0}, 1.5);
+ builder.insertCell({2, 0}, -0.25);
+ builder.insertCell({2, 1}, 0.75);
+ assertTensor("tensor<float>(x[3],y[2])", {0,2.5,1.5,0,-0.25,0.75},
+ *builder.build());
+}
+
TEST("require that cells get default value 0 if not specified") {
- Builder builder(ValueType::from_spec("tensor(x[3])"));
+ BuilderDbl builder(ValueType::from_spec("tensor(x[3])"));
builder.insertCell(1, 11);
assertTensor("tensor(x[3])", {0,11,0},
*builder.build());
}
-void assertTensorCell(const DenseTensor::Address &expAddress,
+void assertTensorCell(const DenseTensorView::Address &expAddress,
double expCell,
- const DenseTensor::CellsIterator &itr)
+ const DenseTensorView::CellsIterator &itr)
{
EXPECT_TRUE(itr.valid());
EXPECT_EQUAL(expAddress, itr.address());
@@ -118,14 +133,14 @@ void assertTensorCell(const DenseTensor::Address &expAddress,
TEST("require that dense tensor cells iterator works for 1d tensor") {
Tensor::UP tensor;
{
- Builder builder(ValueType::from_spec("tensor(x[2])"));
+ BuilderDbl builder(ValueType::from_spec("tensor(x[2])"));
builder.insertCell(0, 2);
builder.insertCell(1, 3);
tensor = builder.build();
}
- const DenseTensor &denseTensor = dynamic_cast<const DenseTensor &>(*tensor);
- DenseTensor::CellsIterator itr = denseTensor.cellsIterator();
+ const DenseTensorView &denseTensor = dynamic_cast<const DenseTensorView &>(*tensor);
+ DenseTensorView::CellsIterator itr = denseTensor.cellsIterator();
assertTensorCell({0}, 2, itr);
itr.next();
@@ -137,7 +152,7 @@ TEST("require that dense tensor cells iterator works for 1d tensor") {
TEST("require that dense tensor cells iterator works for 2d tensor") {
Tensor::UP tensor;
{
- Builder builder(ValueType::from_spec("tensor(x[2],y[2])"));
+ BuilderDbl builder(ValueType::from_spec("tensor(x[2],y[2])"));
builder.insertCell({0, 0}, 2);
builder.insertCell({0, 1}, 3);
builder.insertCell({1, 0}, 5);
@@ -145,8 +160,8 @@ TEST("require that dense tensor cells iterator works for 2d tensor") {
tensor = builder.build();
}
- const DenseTensor &denseTensor = dynamic_cast<const DenseTensor &>(*tensor);
- DenseTensor::CellsIterator itr = denseTensor.cellsIterator();
+ const DenseTensorView &denseTensor = dynamic_cast<const DenseTensorView &>(*tensor);
+ DenseTensorView::CellsIterator itr = denseTensor.cellsIterator();
assertTensorCell({0,0}, 2, itr);
itr.next();
diff --git a/eval/src/tests/tensor/tensor_mapper/.gitignore b/eval/src/tests/tensor/tensor_mapper/.gitignore
deleted file mode 100644
index 8a312ff3157..00000000000
--- a/eval/src/tests/tensor/tensor_mapper/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-vespalib_tensor_mapper_test_app
diff --git a/eval/src/tests/tensor/tensor_mapper/CMakeLists.txt b/eval/src/tests/tensor/tensor_mapper/CMakeLists.txt
deleted file mode 100644
index dfc35b4f018..00000000000
--- a/eval/src/tests/tensor/tensor_mapper/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(eval_tensor_mapper_test_app TEST
- SOURCES
- tensor_mapper_test.cpp
- DEPENDS
- vespaeval
-)
-vespa_add_test(NAME eval_tensor_mapper_test_app COMMAND eval_tensor_mapper_test_app)
diff --git a/eval/src/tests/tensor/tensor_mapper/tensor_mapper_test.cpp b/eval/src/tests/tensor/tensor_mapper/tensor_mapper_test.cpp
deleted file mode 100644
index 60b17930f0b..00000000000
--- a/eval/src/tests/tensor/tensor_mapper/tensor_mapper_test.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include <vespa/eval/eval/simple_tensor.h>
-#include <vespa/eval/eval/tensor_spec.h>
-#include <vespa/eval/tensor/default_tensor_engine.h>
-#include <vespa/eval/tensor/tensor_mapper.h>
-#include <vespa/eval/tensor/test/test_utils.h>
-#include <vespa/eval/tensor/wrapped_simple_tensor.h>
-#include <vespa/vespalib/testkit/test_kit.h>
-#include <vespa/vespalib/util/stringfmt.h>
-
-using vespalib::eval::ValueType;
-using vespalib::eval::Value;
-using vespalib::eval::TensorSpec;
-using vespalib::eval::SimpleTensor;
-using vespalib::tensor::test::makeTensor;
-using namespace vespalib::tensor;
-
-void
-verify_wrapped(const TensorSpec &source, const vespalib::string &type, const TensorSpec &expect)
-{
- auto tensor = std::make_unique<WrappedSimpleTensor>(SimpleTensor::create(source));
- auto mapped = TensorMapper::mapToWrapped(*tensor, ValueType::from_spec(type));
- TensorSpec actual = mapped->toSpec();
- EXPECT_EQUAL(actual, expect);
-}
-
-void
-verify(const TensorSpec &source, const vespalib::string &type, const TensorSpec &expect)
-{
- auto tensor = makeTensor<Tensor>(source);
- TensorMapper mapper(ValueType::from_spec(type));
- auto mapped = mapper.map(*tensor);
- TensorSpec actual = mapped->toSpec();
- EXPECT_EQUAL(actual, expect);
- TEST_DO(verify_wrapped(source, type, expect));
-}
-
-TEST("require that sparse tensors can be mapped to sparse type") {
- TEST_DO(verify(TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","1"}}, 1)
- .add({{"x","2"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","2"}}, 5)
- .add({{"x","2"},{"y","2"}}, 7),
- "tensor(y{})",
- TensorSpec("tensor(y{})")
- .add({{"y","1"}}, 4)
- .add({{"y","2"}}, 12)));
-
- TEST_DO(verify(TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","1"}}, 1)
- .add({{"x","2"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","2"}}, 5)
- .add({{"x","2"},{"y","2"}}, 7),
- "tensor(x{})",
- TensorSpec("tensor(x{})")
- .add({{"x","1"}}, 6)
- .add({{"x","2"}}, 10)));
-}
-
-TEST("require that sparse tensors can be mapped to dense type") {
- TEST_DO(verify(TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","0"}}, 1)
- .add({{"x","2"},{"y","0"}}, 3)
- .add({{"x","1"},{"y","1"}}, 5)
- .add({{"x","2"},{"y","1"}}, 7),
- "tensor(y[3])",
- TensorSpec("tensor(y[3])")
- .add({{"y",0}}, 4)
- .add({{"y",1}}, 12)
- .add({{"y",2}}, 0)));
-
- TEST_DO(verify(TensorSpec("tensor(x{},y{})")
- .add({{"x","1"},{"y","0x"}}, 1)
- .add({{"x","2"},{"y",""}}, 3)
- .add({{"x","1"},{"y","1"}}, 5)
- .add({{"x","2"},{"y","10"}}, 7),
- "tensor(y[3])",
- TensorSpec("tensor(y[3])")
- .add({{"y",0}}, 3)
- .add({{"y",1}}, 5)
- .add({{"y",2}}, 0)));
-
- TEST_DO(verify(TensorSpec("tensor(x{},y{})")
- .add({{"x","0"},{"y","0"}}, 1)
- .add({{"x","1"},{"y","0"}}, 3)
- .add({{"x","0"},{"y","1"}}, 5)
- .add({{"x","10"},{"y","1"}}, 7),
- "tensor(x[2],y[3])",
- TensorSpec("tensor(x[2],y[3])")
- .add({{"x",0},{"y",0}}, 1)
- .add({{"x",0},{"y",1}}, 5)
- .add({{"x",0},{"y",2}}, 0)
- .add({{"x",1},{"y",0}}, 3)
- .add({{"x",1},{"y",1}}, 0)
- .add({{"x",1},{"y",2}}, 0)));
-}
-
-TEST("require that dense tensors can be mapped to sparse type") {
- TEST_DO(verify(TensorSpec("tensor(x[2],y[2])")
- .add({{"x",0},{"y",0}}, 1)
- .add({{"x",0},{"y",1}}, 3)
- .add({{"x",1},{"y",0}}, 5)
- .add({{"x",1},{"y",1}}, 7),
- "tensor(x{})",
- TensorSpec("tensor(x{})")
- .add({{"x","0"}}, 4)
- .add({{"x","1"}}, 12)));
-}
-
-TEST("require that mixed tensors can be mapped to sparse type") {
- TEST_DO(verify(TensorSpec("tensor(x[2],y{})")
- .add({{"x",0},{"y","0"}}, 1)
- .add({{"x",0},{"y","1"}}, 3)
- .add({{"x",1},{"y","0"}}, 5)
- .add({{"x",1},{"y","1"}}, 7),
- "tensor(x{})",
- TensorSpec("tensor(x{})")
- .add({{"x","0"}}, 4)
- .add({{"x","1"}}, 12)));
-}
-
-TEST("require that mixed tensors can be mapped to dense type") {
- TEST_DO(verify(TensorSpec("tensor(x[2],y{})")
- .add({{"x",0},{"y","0"}}, 1)
- .add({{"x",0},{"y","1"}}, 3)
- .add({{"x",1},{"y","0"}}, 5)
- .add({{"x",1},{"y","1"}}, 7),
- "tensor(y[2])",
- TensorSpec("tensor(y[2])")
- .add({{"y",0}}, 6)
- .add({{"y",1}}, 10)));
-}
-
-TEST("require that mixed tensors can be mapped to mixed type") {
- TEST_DO(verify(TensorSpec("tensor(x[2],y{})")
- .add({{"x",0},{"y","0"}}, 1)
- .add({{"x",0},{"y","1"}}, 3)
- .add({{"x",1},{"y","0"}}, 5)
- .add({{"x",1},{"y","1"}}, 7),
- "tensor(x{},y[2])",
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","0"},{"y",0}}, 1)
- .add({{"x","0"},{"y",1}}, 3)
- .add({{"x","1"},{"y",0}}, 5)
- .add({{"x","1"},{"y",1}}, 7)));
-}
-
-TEST("require that dense tensors can be mapped to mixed type") {
- TEST_DO(verify(TensorSpec("tensor(x[2],y[2])")
- .add({{"x",0},{"y",0}}, 1)
- .add({{"x",0},{"y",1}}, 3)
- .add({{"x",1},{"y",0}}, 5)
- .add({{"x",1},{"y",1}}, 7),
- "tensor(x{},y[2])",
- TensorSpec("tensor(x{},y[2])")
- .add({{"x","0"},{"y",0}}, 1)
- .add({{"x","0"},{"y",1}}, 3)
- .add({{"x","1"},{"y",0}}, 5)
- .add({{"x","1"},{"y",1}}, 7)));
-}
-
-TEST("require that sparse tensors can be mapped to mixed type") {
- TEST_DO(verify(TensorSpec("tensor(x{},y{})")
- .add({{"x","0"},{"y","0"}}, 1)
- .add({{"x","0"},{"y","1"}}, 3)
- .add({{"x","1"},{"y","0"}}, 5)
- .add({{"x","1"},{"y","1"}}, 7),
- "tensor(x[2],y{})",
- TensorSpec("tensor(x[2],y{})")
- .add({{"x",0},{"y","0"}}, 1)
- .add({{"x",0},{"y","1"}}, 3)
- .add({{"x",1},{"y","0"}}, 5)
- .add({{"x",1},{"y","1"}}, 7)));
-}
-
-TEST("require that missing dimensions are added appropriately") {
- TEST_DO(verify(TensorSpec("tensor(x{})")
- .add({{"x","foo"}}, 42),
- "tensor(x{},y{})",
- TensorSpec("tensor(x{},y{})")
- .add({{"x","foo"},{"y",""}}, 42)));
-
- TEST_DO(verify(TensorSpec("tensor(x[1])")
- .add({{"x",0}}, 42),
- "tensor(x[1],y[1],z[2])",
- TensorSpec("tensor(x[1],y[1],z[2])")
- .add({{"x",0},{"y",0},{"z",0}}, 42)
- .add({{"x",0},{"y",0},{"z",1}}, 0)));
-
- TEST_DO(verify(TensorSpec("tensor(a{})")
- .add({{"a","foo"}}, 42),
- "tensor(a{},b[1],c{},d[2])",
- TensorSpec("tensor(a{},b[1],c{},d[2])")
- .add({{"a","foo"},{"b",0},{"c",""},{"d",0}}, 42)
- .add({{"a","foo"},{"b",0},{"c",""},{"d",1}}, 0)));
-}
-
-TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/vespa/eval/eval/value_type.h b/eval/src/vespa/eval/eval/value_type.h
index 81788c933d7..423c8e15d92 100644
--- a/eval/src/vespa/eval/eval/value_type.h
+++ b/eval/src/vespa/eval/eval/value_type.h
@@ -16,7 +16,7 @@ class ValueType
{
public:
enum class Type { ERROR, DOUBLE, TENSOR };
- enum class CellType { FLOAT, DOUBLE };
+ enum class CellType : char { FLOAT, DOUBLE };
struct Dimension {
using size_type = uint32_t;
static constexpr size_type npos = -1;
@@ -85,4 +85,9 @@ public:
std::ostream &operator<<(std::ostream &os, const ValueType &type);
-}
+// utility template
+template <typename T> inline bool check_cell_type(ValueType::CellType type);
+template <> inline bool check_cell_type<double>(ValueType::CellType type) { return (type == ValueType::CellType::DOUBLE); }
+template <> inline bool check_cell_type<float>(ValueType::CellType type) { return (type == ValueType::CellType::FLOAT); }
+
+} // namespace
diff --git a/eval/src/vespa/eval/tensor/CMakeLists.txt b/eval/src/vespa/eval/tensor/CMakeLists.txt
index 4e9940d3c0a..bc0a4d340b8 100644
--- a/eval/src/vespa/eval/tensor/CMakeLists.txt
+++ b/eval/src/vespa/eval/tensor/CMakeLists.txt
@@ -5,6 +5,5 @@ vespa_add_library(eval_tensor OBJECT
tensor.cpp
tensor_address.cpp
tensor_apply.cpp
- tensor_mapper.cpp
wrapped_simple_tensor.cpp
)
diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp
index dc658d0b2da..58db90f5557 100644
--- a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp
+++ b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp
@@ -7,7 +7,7 @@
#include "sparse/sparse_tensor_address_builder.h"
#include "sparse/direct_sparse_tensor_builder.h"
#include "dense/dense_tensor.h"
-#include "dense/direct_dense_tensor_builder.h"
+#include "dense/typed_dense_tensor_builder.h"
#include "dense/dense_dot_product_function.h"
#include "dense/dense_xw_product_function.h"
#include "dense/dense_fast_rename_optimizer.h"
@@ -159,6 +159,24 @@ DefaultTensorEngine::to_spec(const Value &value) const
}
}
+struct CallDenseTensorBuilder {
+ template <typename CT>
+ static Value::UP
+ call(const ValueType &type, const TensorSpec &spec)
+ {
+ TypedDenseTensorBuilder<CT> builder(type);
+ for (const auto &cell: spec.cells()) {
+ const auto &address = cell.first;
+ size_t cell_idx = calculate_cell_index(type, address);
+ if (cell_idx == UNDEFINED_IDX) {
+ bad_spec(spec);
+ }
+ builder.insertCell(cell_idx, cell.second);
+ }
+ return builder.build();
+ }
+};
+
Value::UP
DefaultTensorEngine::from_spec(const TensorSpec &spec) const
{
@@ -169,16 +187,7 @@ DefaultTensorEngine::from_spec(const TensorSpec &spec) const
double value = spec.cells().empty() ? 0.0 : spec.cells().begin()->second.value;
return std::make_unique<DoubleValue>(value);
} else if (type.is_dense()) {
- DirectDenseTensorBuilder builder(type);
- for (const auto &cell: spec.cells()) {
- const auto &address = cell.first;
- size_t cell_idx = calculate_cell_index(type, address);
- if (cell_idx == UNDEFINED_IDX) {
- bad_spec(spec);
- }
- builder.insertCell(cell_idx, cell.second);
- }
- return builder.build();
+ return dispatch_0<CallDenseTensorBuilder>(type.cell_type(), type, spec);
} else if (type.is_sparse()) {
DirectSparseTensorBuilder builder(type);
SparseTensorAddressBuilder address_builder;
@@ -223,7 +232,7 @@ DefaultTensorEngine::encode(const Value &value, nbostream &output) const
if (auto tensor = value.as_tensor()) {
TypedBinaryFormat::serialize(output, static_cast<const tensor::Tensor &>(*tensor));
} else {
- TypedBinaryFormat::serialize(output, DenseTensor(ValueType::double_type(), {value.as_double()}));
+ TypedBinaryFormat::serialize(output, DenseTensor<double>(ValueType::double_type(), {value.as_double()}));
}
}
@@ -357,12 +366,18 @@ size_t vector_size(const ValueType &type, const vespalib::string &dimension) {
}
}
+struct CallAppendVector {
+ template <typename CT>
+ static void call(const ConstArrayRef<CT> &arr, double *&pos) {
+ for (CT cell : arr) { *pos++ = cell; }
+ }
+};
+
void append_vector(double *&pos, const Value &value) {
if (auto tensor = value.as_tensor()) {
const DenseTensorView *view = static_cast<const DenseTensorView *>(tensor);
- for (double cell: view->cellsRef()) {
- *pos++ = cell;
- }
+ TypedCells cellsRef = view->cellsRef();
+ dispatch_1<CallAppendVector>(cellsRef, pos);
} else {
*pos++ = value.as_double();
}
@@ -375,7 +390,7 @@ const Value &concat_vectors(const Value &a, const Value &b, const vespalib::stri
append_vector(pos, b);
assert(pos == cells.end());
const ValueType &type = stash.create<ValueType>(ValueType::tensor_type({ValueType::Dimension(dimension, vector_size)}));
- return stash.create<DenseTensorView>(type, cells);
+ return stash.create<DenseTensorView>(type, TypedCells(cells));
}
const Value &
diff --git a/eval/src/vespa/eval/tensor/dense/CMakeLists.txt b/eval/src/vespa/eval/tensor/dense/CMakeLists.txt
index ce20d6ba6d9..78723fddc17 100644
--- a/eval/src/vespa/eval/tensor/dense/CMakeLists.txt
+++ b/eval/src/vespa/eval/tensor/dense/CMakeLists.txt
@@ -16,7 +16,8 @@ vespa_add_library(eval_tensor_dense OBJECT
dense_tensor_reduce.cpp
dense_tensor_view.cpp
dense_xw_product_function.cpp
- direct_dense_tensor_builder.cpp
mutable_dense_tensor_view.cpp
+ typed_cells.cpp
+ typed_dense_tensor_builder.cpp
vector_from_doubles_function.cpp
)
diff --git a/eval/src/vespa/eval/tensor/dense/dense_dot_product_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_dot_product_function.cpp
index 988edba7d55..c925f288c4a 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_dot_product_function.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_dot_product_function.cpp
@@ -9,7 +9,6 @@
namespace vespalib::tensor {
-using CellsRef = DenseTensorView::CellsRef;
using eval::ValueType;
using eval::TensorFunction;
using eval::as;
@@ -19,17 +18,19 @@ using namespace eval::operation;
namespace {
-CellsRef getCellsRef(const eval::Value &value) {
+TypedCells getCellsRef(const eval::Value &value) {
const DenseTensorView &denseTensor = static_cast<const DenseTensorView &>(value);
return denseTensor.cellsRef();
}
void my_dot_product_op(eval::InterpretedFunction::State &state, uint64_t param) {
auto *hw_accelerator = (hwaccelrated::IAccelrated *)(param);
- DenseTensorView::CellsRef lhsCells = getCellsRef(state.peek(1));
- DenseTensorView::CellsRef rhsCells = getCellsRef(state.peek(0));
- size_t numCells = std::min(lhsCells.size(), rhsCells.size());
- double result = hw_accelerator->dotProduct(lhsCells.cbegin(), rhsCells.cbegin(), numCells);
+ TypedCells lhsCells = getCellsRef(state.peek(1));
+ TypedCells rhsCells = getCellsRef(state.peek(0));
+ size_t numCells = std::min(lhsCells.size, rhsCells.size);
+ const ConstArrayRef<double> lhs = lhsCells.typify<double>();
+ const ConstArrayRef<double> rhs = rhsCells.typify<double>();
+ double result = hw_accelerator->dotProduct(lhs.cbegin(), rhs.cbegin(), numCells);
state.pop_pop_push(state.stash.create<eval::DoubleValue>(result));
}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp b/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp
index 09977df25b7..d8e1876ac64 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp
@@ -9,7 +9,6 @@
namespace vespalib::tensor {
-using CellsRef = DenseTensorView::CellsRef;
using eval::Value;
using eval::ValueType;
using eval::TensorFunction;
diff --git a/eval/src/vespa/eval/tensor/dense/dense_inplace_join_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_inplace_join_function.cpp
index ce6b1743951..5fdfdbc4e9f 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_inplace_join_function.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_inplace_join_function.cpp
@@ -9,7 +9,6 @@
namespace vespalib::tensor {
-using CellsRef = DenseTensorView::CellsRef;
using eval::Value;
using eval::ValueType;
using eval::TensorFunction;
@@ -18,7 +17,7 @@ using namespace eval::tensor_function;
namespace {
-CellsRef getCellsRef(const eval::Value &value) {
+TypedCells getCellsRef(const eval::Value &value) {
const DenseTensorView &denseTensor = static_cast<const DenseTensorView &>(value);
return denseTensor.cellsRef();
}
@@ -26,8 +25,8 @@ CellsRef getCellsRef(const eval::Value &value) {
template <bool write_left>
void my_inplace_join_op(eval::InterpretedFunction::State &state, uint64_t param) {
join_fun_t function = (join_fun_t)param;
- CellsRef lhs_cells = getCellsRef(state.peek(1));
- CellsRef rhs_cells = getCellsRef(state.peek(0));
+ ConstArrayRef<double> lhs_cells = getCellsRef(state.peek(1)).typify<double>();
+ ConstArrayRef<double> rhs_cells = getCellsRef(state.peek(0)).typify<double>();
auto dst_cells = unconstify(write_left ? lhs_cells : rhs_cells);
for (size_t i = 0; i < dst_cells.size(); ++i) {
dst_cells[i] = function(lhs_cells[i], rhs_cells[i]);
diff --git a/eval/src/vespa/eval/tensor/dense/dense_inplace_map_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_inplace_map_function.cpp
index c72889ca0ed..b38a6b175dc 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_inplace_map_function.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_inplace_map_function.cpp
@@ -8,7 +8,6 @@
namespace vespalib::tensor {
-using CellsRef = DenseTensorView::CellsRef;
using eval::Value;
using eval::ValueType;
using eval::TensorFunction;
@@ -19,7 +18,7 @@ namespace {
ArrayRef<double> getMutableCells(const eval::Value &value) {
const DenseTensorView &denseTensor = static_cast<const DenseTensorView &>(value);
- return unconstify(denseTensor.cellsRef());
+ return unconstify(denseTensor.cellsRef().typify<double>());
}
void my_inplace_map_op(eval::InterpretedFunction::State &state, uint64_t param) {
diff --git a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp
index 9deac5437e0..b81b0f2c876 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp
@@ -6,7 +6,6 @@
namespace vespalib::tensor {
-using CellsRef = DenseTensorView::CellsRef;
using eval::Value;
using eval::ValueType;
using eval::TensorFunction;
@@ -15,14 +14,14 @@ using namespace eval::tensor_function;
namespace {
-CellsRef getCellsRef(const eval::Value &value) {
+TypedCells getCellsRef(const eval::Value &value) {
const DenseTensorView &denseTensor = static_cast<const DenseTensorView &>(value);
return denseTensor.cellsRef();
}
void my_replace_type_op(eval::InterpretedFunction::State &state, uint64_t param) {
const ValueType *type = (const ValueType *)(param);
- CellsRef cells = getCellsRef(state.peek(0));
+ TypedCells cells = getCellsRef(state.peek(0));
state.pop_push(state.stash.create<DenseTensorView>(*type, cells));
}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp
index c183e5c1db3..73cdfc12a38 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp
@@ -21,68 +21,57 @@ calcCellsSize(const eval::ValueType &type)
return cellsSize;
}
+template<typename T>
void
-checkCellsSize(const DenseTensor &arg)
+checkCellsSize(const DenseTensor<T> &arg)
{
auto cellsSize = calcCellsSize(arg.fast_type());
- if (arg.cellsRef().size() != cellsSize) {
+ if (arg.cellsRef().size != cellsSize) {
throw IllegalStateException(make_string("Wrong cell size, "
"expected=%zu, "
"actual=%zu",
cellsSize,
- arg.cellsRef().size()));
+ arg.cellsRef().size));
+ }
+ if (arg.fast_type().cell_type() != arg.cellsRef().type) {
+ throw IllegalStateException(make_string("Wrong cell type, "
+ "expected=%u, "
+ "actual=%u",
+ (unsigned char)arg.fast_type().cell_type(),
+ (unsigned char)arg.cellsRef().type));
}
}
}
-DenseTensor::DenseTensor()
- : DenseTensorView(_type),
- _type(eval::ValueType::double_type()),
- _cells(1)
-{
- initCellsRef(CellsRef(_cells));
-}
-
-DenseTensor::DenseTensor(const eval::ValueType &type_in,
- const Cells &cells_in)
- : DenseTensorView(_type),
- _type(type_in),
- _cells(cells_in)
-{
- initCellsRef(CellsRef(_cells));
- checkCellsSize(*this);
-}
-
-
-DenseTensor::DenseTensor(const eval::ValueType &type_in,
- Cells &&cells_in)
- : DenseTensorView(_type),
- _type(type_in),
- _cells(std::move(cells_in))
-{
- initCellsRef(CellsRef(_cells));
- checkCellsSize(*this);
-}
-
-DenseTensor::DenseTensor(eval::ValueType &&type_in,
- Cells &&cells_in)
+template <typename CT>
+DenseTensor<CT>::DenseTensor(eval::ValueType type_in,
+ std::vector<CT> &&cells_in)
: DenseTensorView(_type),
_type(std::move(type_in)),
_cells(std::move(cells_in))
{
- initCellsRef(CellsRef(_cells));
+ initCellsRef(TypedCells(_cells));
checkCellsSize(*this);
}
-DenseTensor::~DenseTensor() = default;
+template <typename CT>
+DenseTensor<CT>::~DenseTensor() = default;
+template <typename CT>
+template <typename RCT>
bool
-DenseTensor::operator==(const DenseTensor &rhs) const
+DenseTensor<CT>::operator==(const DenseTensor<RCT> &rhs) const
{
- return (_type == rhs._type) &&
- (_cells == rhs._cells);
+ if (_type != rhs._type) return false;
+ if (_cells.size != rhs._cells.size) return false;
+ for (size_t i = 0; i < _cells.size; i++) {
+ if (_cells[i] != rhs._cells[i]) return false;
+ }
+ return true;
}
-}
+template class DenseTensor<float>;
+template class DenseTensor<double>;
+}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor.h b/eval/src/vespa/eval/tensor/dense/dense_tensor.h
index 3795831c914..d0246fef635 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor.h
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor.h
@@ -10,20 +10,20 @@ namespace vespalib::tensor {
* A dense tensor where all dimensions are indexed.
* Tensor cells are stored in an underlying array according to the order of the dimensions.
*/
+template <typename CT>
class DenseTensor : public DenseTensorView
{
public:
- DenseTensor();
+ DenseTensor() = delete;
~DenseTensor() override;
- DenseTensor(const eval::ValueType &type_in, const Cells &cells_in);
- DenseTensor(const eval::ValueType &type_in, Cells &&cells_in);
- DenseTensor(eval::ValueType &&type_in, Cells &&cells_in);
- bool operator==(const DenseTensor &rhs) const;
+ DenseTensor(eval::ValueType type_in, std::vector<CT> &&cells_in);
+
+ // for unit tests
+ template <typename RCT>
+ bool operator==(const DenseTensor<RCT> &rhs) const;
private:
eval::ValueType _type;
- Cells _cells;
-
+ std::vector<CT> _cells;
};
}
-
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp
index 09bc546c982..c1c24d28b7f 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.cpp
@@ -25,7 +25,7 @@ DenseTensorAddressMapper::mapLabelToNumber(stringref label)
}
uint32_t
-DenseTensorAddressMapper::mapAddressToIndex(const TensorAddress &address, const eval::ValueType type)
+DenseTensorAddressMapper::mapAddressToIndex(const TensorAddress &address, const eval::ValueType &type)
{
uint32_t idx = 0;
TensorAddressElementIterator<TensorAddress> addressIterator(address);
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h
index cf20fc6ad3c..7cd776a260c 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_address_mapper.h
@@ -21,7 +21,7 @@ public:
static constexpr uint32_t BAD_LABEL = std::numeric_limits<uint32_t>::max();
static constexpr uint32_t BAD_ADDRESS = std::numeric_limits<uint32_t>::max();
static uint32_t mapLabelToNumber(stringref label);
- static uint32_t mapAddressToIndex(const TensorAddress &address, const eval::ValueType type);
+ static uint32_t mapAddressToIndex(const TensorAddress &address, const eval::ValueType &type);
};
}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.h
index 49e075f6999..cd524b27171 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.h
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.h
@@ -4,7 +4,6 @@
namespace vespalib::tensor {
class Tensor;
- class DenseTensor;
}
namespace vespalib::tensor::dense {
@@ -17,6 +16,7 @@ namespace vespalib::tensor::dense {
template <typename Function>
std::unique_ptr<Tensor>
apply(const DenseTensorView &lhs, const Tensor &rhs, Function &&func);
+
template <typename Function>
std::unique_ptr<Tensor>
apply(const DenseTensorView &lhs, const DenseTensorView &rhs, Function &&func);
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.hpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.hpp
index e71840f392c..409e1ad087f 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.hpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.hpp
@@ -4,21 +4,23 @@
#include "dense_tensor_apply.h"
#include "dense_dimension_combiner.h"
-#include "direct_dense_tensor_builder.h"
+#include "typed_dense_tensor_builder.h"
namespace vespalib::tensor::dense {
-template <typename Function>
+template <typename LCT, typename RCT, typename OCT, typename Function>
std::unique_ptr<Tensor>
-apply(DenseDimensionCombiner & combiner, DirectDenseTensorBuilder & builder,
- const DenseTensorView::CellsRef & lhsCells,
- const DenseTensorView::CellsRef & rhsCells, Function &&func) __attribute__((noinline));
+apply(DenseDimensionCombiner & combiner,
+ TypedDenseTensorBuilder<OCT> & builder,
+ const ConstArrayRef<LCT> & lhsCells,
+ const ConstArrayRef<RCT> & rhsCells, Function &&func) __attribute__((noinline));
-template <typename Function>
+template <typename LCT, typename RCT, typename OCT, typename Function>
std::unique_ptr<Tensor>
-apply(DenseDimensionCombiner & combiner, DirectDenseTensorBuilder & builder,
- const DenseTensorView::CellsRef & lhsCells,
- const DenseTensorView::CellsRef & rhsCells, Function &&func)
+apply(DenseDimensionCombiner & combiner,
+ TypedDenseTensorBuilder<OCT> & builder,
+ const ConstArrayRef<LCT> & lhsCells,
+ const ConstArrayRef<RCT> & rhsCells, Function &&func)
{
for (combiner.leftReset(); combiner.leftInRange(); combiner.stepLeft()) {
for (combiner.rightReset(); combiner.rightInRange(); combiner.stepRight()) {
@@ -33,6 +35,20 @@ apply(DenseDimensionCombiner & combiner, DirectDenseTensorBuilder & builder,
return builder.build();
}
+struct CallApply {
+ template <typename LCT, typename RCT, typename Function>
+ static std::unique_ptr<Tensor>
+ call(const ConstArrayRef<LCT> & lhsArr,
+ const ConstArrayRef<RCT> & rhsArr,
+ DenseDimensionCombiner & combiner,
+ Function &&func)
+ {
+ using OCT = typename OutputCellType<LCT, RCT>::output_type;
+ TypedDenseTensorBuilder<OCT> builder(combiner.result_type);
+ return apply(combiner, builder, lhsArr, rhsArr, std::move(func));
+ }
+};
+
template <typename Function>
std::unique_ptr<Tensor>
apply(const DenseTensorView &lhs, const Tensor &rhs, Function &&func)
@@ -40,8 +56,9 @@ apply(const DenseTensorView &lhs, const Tensor &rhs, Function &&func)
const DenseTensorView *view = dynamic_cast<const DenseTensorView *>(&rhs);
if (view) {
DenseDimensionCombiner combiner(lhs.fast_type(), view->fast_type());
- DirectDenseTensorBuilder builder(combiner.result_type);
- return apply(combiner, builder, lhs.cellsRef(), view->cellsRef(), std::move(func));
+ TypedCells lhsCells = lhs.cellsRef();
+ TypedCells rhsCells = view->cellsRef();
+ return dispatch_2<CallApply>(lhsCells, rhsCells, combiner, std::move(func));
}
return Tensor::UP();
}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp
index 15c09db44b3..55d0e29bc35 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.cpp
@@ -4,7 +4,7 @@
namespace vespalib::tensor {
-DenseTensorCellsIterator::DenseTensorCellsIterator(const eval::ValueType &type_in, CellsRef cells)
+DenseTensorCellsIterator::DenseTensorCellsIterator(const eval::ValueType &type_in, TypedCells cells)
: _type(type_in),
_cells(cells),
_cellIdx(0),
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h
index caf92d6c8c7..8d189027be2 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_cells_iterator.h
@@ -4,6 +4,7 @@
#include <vespa/eval/eval/value_type.h>
#include <vespa/vespalib/util/arrayref.h>
+#include "typed_cells.h"
namespace vespalib::tensor {
@@ -16,14 +17,14 @@ public:
using size_type = eval::ValueType::Dimension::size_type;
using Address = std::vector<size_type>;
private:
- using CellsRef = vespalib::ConstArrayRef<double>;
+
const eval::ValueType &_type;
- CellsRef _cells;
+ TypedCells _cells;
size_t _cellIdx;
const int32_t _lastDimension;
Address _address;
public:
- DenseTensorCellsIterator(const eval::ValueType &type_in, CellsRef cells);
+ DenseTensorCellsIterator(const eval::ValueType &type_in, TypedCells cells);
~DenseTensorCellsIterator();
void next() {
++_cellIdx;
@@ -37,8 +38,8 @@ public:
}
}
}
- bool valid() const { return _cellIdx < _cells.size(); }
- double cell() const { return _cells[_cellIdx]; }
+ bool valid() const { return _cellIdx < _cells.size; }
+ double cell() const { return _cells.get(_cellIdx); }
const Address &address() const { return _address; }
const eval::ValueType &fast_type() const { return _type; }
};
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp
index 4e2940f2516..4777abcbdef 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.cpp
@@ -6,28 +6,37 @@
namespace vespalib::tensor {
-DenseTensorModify::DenseTensorModify(join_fun_t op, const eval::ValueType &type, Cells cells)
+template <class CT>
+DenseTensorModify<CT>::DenseTensorModify(join_fun_t op, const eval::ValueType &type, std::vector<CT> &&cells)
: _op(op),
_type(type),
_cells(std::move(cells))
{
+ assert(vespalib::eval::check_cell_type<CT>(type.cell_type()));
}
-
-DenseTensorModify::~DenseTensorModify() = default;
+template <class CT>
+DenseTensorModify<CT>::~DenseTensorModify() = default;
+
+template <class CT>
void
-DenseTensorModify::visit(const TensorAddress &address, double value)
+DenseTensorModify<CT>::visit(const TensorAddress &address, double value)
{
uint32_t idx = DenseTensorAddressMapper::mapAddressToIndex(address, _type);
if (idx != DenseTensorAddressMapper::BAD_ADDRESS) {
- _cells[idx] = _op(_cells[idx], value);
+ double nv = _op(_cells[idx], value);
+ _cells[idx] = (CT) nv;
}
}
+template <class CT>
std::unique_ptr<Tensor>
-DenseTensorModify::build()
+DenseTensorModify<CT>::build()
{
- return std::make_unique<DenseTensor>(std::move(_type), std::move(_cells));
+ return std::make_unique<DenseTensor<CT>>(_type, std::move(_cells));
}
-}
+template class DenseTensorModify<float>;
+template class DenseTensorModify<double>;
+
+} // namespace
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h
index 848e6e559c2..3d975c8595e 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_modify.h
@@ -12,16 +12,16 @@ namespace vespalib::tensor {
* For all cells visited, a join function is applied to determine
* the new cell value.
*/
+template <class CT>
class DenseTensorModify : public TensorVisitor
{
using join_fun_t = Tensor::join_fun_t;
- using Cells = DenseTensorView::Cells;
join_fun_t _op;
- eval::ValueType _type;
- Cells _cells;
+ const eval::ValueType &_type;
+ std::vector<CT> _cells;
public:
- DenseTensorModify(join_fun_t op, const eval::ValueType &type, Cells cells);
+ DenseTensorModify(join_fun_t op, const eval::ValueType &type, std::vector<CT> &&cells);
~DenseTensorModify();
void visit(const TensorAddress &address, double value) override;
std::unique_ptr<Tensor> build();
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp
index 41643d8c266..252be199208 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.cpp
@@ -4,10 +4,8 @@
namespace vespalib::tensor::dense {
-namespace {
-
size_t
-calcCellsSize(const eval::ValueType &type)
+DimensionReducer::calcCellsSize(const eval::ValueType &type)
{
size_t cellsSize = 1;
for (const auto &dim : type.dimensions()) {
@@ -16,11 +14,9 @@ calcCellsSize(const eval::ValueType &type)
return cellsSize;
}
-}
DimensionReducer::DimensionReducer(const eval::ValueType &oldType,
const string &dimensionToRemove)
: _type(oldType.reduce({ dimensionToRemove })),
- _cellsResult(calcCellsSize(_type)),
_innerDimSize(1),
_sumDimSize(1),
_outerDimSize(1)
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp
index 98db89dd2a7..5673a35c7e6 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_reduce.hpp
@@ -6,29 +6,27 @@
namespace vespalib::tensor::dense {
-using Cells = DenseTensorView::Cells;
-using CellsRef = DenseTensorView::CellsRef;
-
class DimensionReducer
{
private:
eval::ValueType _type;
- Cells _cellsResult;
size_t _innerDimSize;
size_t _sumDimSize;
size_t _outerDimSize;
+ static size_t calcCellsSize(const eval::ValueType &type);
void setup(const eval::ValueType &oldType, const vespalib::string &dimensionToRemove);
-
public:
DimensionReducer(const eval::ValueType &oldType, const string &dimensionToRemove);
~DimensionReducer();
- template <typename Function>
+ template <typename T, typename Function>
std::unique_ptr<DenseTensorView>
- reduceCells(CellsRef cellsIn, Function &&func) {
+ reduceCells(ConstArrayRef<T> cellsIn, Function &&func) {
+ size_t resultSize = calcCellsSize(_type);
+ std::vector<T> cellsOut(resultSize);
auto itr_in = cellsIn.cbegin();
- auto itr_out = _cellsResult.begin();
+ auto itr_out = cellsOut.begin();
for (size_t outerDim = 0; outerDim < _outerDimSize; ++outerDim) {
auto saved_itr = itr_out;
for (size_t innerDim = 0; innerDim < _innerDimSize; ++innerDim) {
@@ -45,20 +43,47 @@ public:
}
}
}
- assert(itr_out == _cellsResult.end());
+ assert(itr_out == cellsOut.end());
assert(itr_in == cellsIn.cend());
- return std::make_unique<DenseTensor>(std::move(_type), std::move(_cellsResult));
+ return std::make_unique<DenseTensor<T>>(std::move(_type), std::move(cellsOut));
}
};
namespace {
+struct CallReduceCells {
+ template <typename CT, typename Function>
+ static std::unique_ptr<DenseTensorView>
+ call(const ConstArrayRef<CT> &oldCells, DimensionReducer &reducer, Function &&func) {
+ return reducer.reduceCells(oldCells, func);
+ }
+
+ template <typename CT, typename Function>
+ static double
+ call(const ConstArrayRef<CT> &oldCells, Function &&func) {
+ assert(oldCells.size() > 0);
+ double result = oldCells[0];
+ for (size_t i = 1; i < oldCells.size(); ++i) {
+ result = func(result, oldCells[i]);
+ }
+ return result;
+ }
+};
+
template <typename Function>
std::unique_ptr<DenseTensorView>
reduce(const DenseTensorView &tensor, const vespalib::string &dimensionToRemove, Function &&func)
{
DimensionReducer reducer(tensor.fast_type(), dimensionToRemove);
- return reducer.reduceCells(tensor.cellsRef(), func);
+ TypedCells oldCells = tensor.cellsRef();
+ return dispatch_1<CallReduceCells>(oldCells, reducer, func);
+}
+
+template <typename Function>
+double
+reduce_all_dimensions(TypedCells oldCells, Function &&func)
+{
+ return dispatch_1<CallReduceCells>(oldCells, func);
}
}
@@ -67,18 +92,21 @@ template <typename Function>
std::unique_ptr<Tensor>
reduce(const DenseTensorView &tensor, const std::vector<vespalib::string> &dimensions, Function &&func)
{
- if (dimensions.size() == 1) {
- return reduce(tensor, dimensions[0], func);
- } else if (dimensions.size() > 0) {
- std::unique_ptr<DenseTensorView> result = reduce(tensor, dimensions[0], func);
- for (size_t i = 1; i < dimensions.size(); ++i) {
- std::unique_ptr<DenseTensorView> tmpResult = reduce(*result, dimensions[i], func);
- result = std::move(tmpResult);
- }
- return result;
- } else {
- return std::unique_ptr<Tensor>();
+ if ((dimensions.size() == 0) ||
+ (dimensions.size() == tensor.fast_type().dimensions().size()))
+ {
+ eval::ValueType newType = tensor.fast_type().reduce(dimensions);
+ assert(newType.is_double());
+ double result = reduce_all_dimensions(tensor.cellsRef(), func);
+ std::vector<double> newCells({result});
+ return std::make_unique<DenseTensor<double>>(std::move(newType), std::move(newCells));
+ }
+ std::unique_ptr<DenseTensorView> result = reduce(tensor, dimensions[0], func);
+ for (size_t i = 1; i < dimensions.size(); ++i) {
+ std::unique_ptr<DenseTensorView> tmpResult = reduce(*result, dimensions[i], func);
+ result = std::move(tmpResult);
}
+ return result;
}
}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp
index 73b2e7b3ffb..1ae198d1171 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp
@@ -54,12 +54,12 @@ void
checkCellsSize(const DenseTensorView &arg)
{
auto cellsSize = calcCellsSize(arg.fast_type());
- if (arg.cellsRef().size() != cellsSize) {
+ if (arg.cellsRef().size != cellsSize) {
throw IllegalStateException(make_string("wrong cell size, "
"expected=%zu, "
"actual=%zu",
cellsSize,
- arg.cellsRef().size()));
+ arg.cellsRef().size));
}
}
@@ -67,7 +67,7 @@ void
checkDimensions(const DenseTensorView &lhs, const DenseTensorView &rhs,
vespalib::stringref operation)
{
- if (lhs.fast_type() != rhs.fast_type()) {
+ if (lhs.fast_type().dimensions() != rhs.fast_type().dimensions()) {
throw IllegalStateException(make_string("mismatching dimensions for "
"dense tensor %s, "
"lhs dimensions = '%s', "
@@ -87,24 +87,52 @@ checkDimensions(const DenseTensorView &lhs, const DenseTensorView &rhs,
* The given function is used to calculate the resulting cell value
* for overlapping cells.
*/
+template <typename LCT, typename RCT, typename Function>
+static Tensor::UP
+sameShapeJoin(const ConstArrayRef<LCT> &lhs, const ConstArrayRef<RCT> &rhs,
+ const eval::ValueType &lhs_type,
+ Function &&func)
+{
+ size_t sz = lhs.size();
+ assert(sz == rhs.size());
+ using OutputSelector = OutputCellType<LCT, RCT>;
+ using OCT = typename OutputSelector::output_type;
+ std::vector<OCT> newCells;
+ newCells.reserve(sz);
+ auto rhsCellItr = rhs.cbegin();
+ for (const auto &lhsCell : lhs) {
+ OCT v = func(lhsCell, *rhsCellItr);
+ newCells.push_back(v);
+ ++rhsCellItr;
+ }
+ assert(rhsCellItr == rhs.cend());
+ assert(newCells.size() == sz);
+ auto newType = eval::ValueType::tensor_type(lhs_type.dimensions(), OutputSelector::output_cell_type());
+ return std::make_unique<DenseTensor<OCT>>(std::move(newType), std::move(newCells));
+}
+
+struct CallJoin
+{
+ template <typename LCT, typename RCT, typename Function>
+ static Tensor::UP
+ call(const ConstArrayRef<LCT> &lhs, const ConstArrayRef<RCT> &rhs,
+ const eval::ValueType &lhs_type,
+ Function &&func)
+ {
+ return sameShapeJoin(lhs, rhs, lhs_type, std::move(func));
+ }
+};
+
template <typename Function>
Tensor::UP
joinDenseTensors(const DenseTensorView &lhs, const DenseTensorView &rhs,
Function &&func)
{
- DenseTensor::Cells cells;
- cells.reserve(lhs.cellsRef().size());
- auto rhsCellItr = rhs.cellsRef().cbegin();
- for (const auto &lhsCell : lhs.cellsRef()) {
- cells.push_back(func(lhsCell, *rhsCellItr));
- ++rhsCellItr;
- }
- assert(rhsCellItr == rhs.cellsRef().cend());
- return std::make_unique<DenseTensor>(lhs.fast_type(),
- std::move(cells));
+ TypedCells lhsCells = lhs.cellsRef();
+ TypedCells rhsCells = rhs.cellsRef();
+ return dispatch_2<CallJoin>(lhsCells, rhsCells, lhs.fast_type(), std::move(func));
}
-
template <typename Function>
Tensor::UP
joinDenseTensors(const DenseTensorView &lhs, const Tensor &rhs,
@@ -119,13 +147,13 @@ joinDenseTensors(const DenseTensorView &lhs, const Tensor &rhs,
return Tensor::UP();
}
-bool sameCells(DenseTensorView::CellsRef lhs, DenseTensorView::CellsRef rhs)
+bool sameCells(TypedCells lhs, TypedCells rhs)
{
- if (lhs.size() != rhs.size()) {
+ if (lhs.size != rhs.size) {
return false;
}
- for (size_t i = 0; i < lhs.size(); ++i) {
- if (lhs[i] != rhs[i]) {
+ for (size_t i = 0; i < lhs.size; ++i) {
+ if (lhs.get(i) != rhs.get(i)) {
return false;
}
}
@@ -146,27 +174,43 @@ DenseTensorView::type() const
return _typeRef;
}
+struct CallSum {
+ template <typename CT>
+ static double
+ call(const ConstArrayRef<CT> &arr) {
+ double res = 0.0;
+ for (CT val : arr) {
+ res += val;
+ }
+ return res;
+ }
+};
+
double
DenseTensorView::as_double() const
{
- double result = 0.0;
- for (const auto &cell : _cellsRef) {
- result += cell;
- }
- return result;
+ return dispatch_1<CallSum>(_cellsRef);
}
+struct CallApply {
+ template <typename CT>
+ static Tensor::UP
+ call(const ConstArrayRef<CT> &oldCells, const eval::ValueType &newType, const CellFunction &func)
+ {
+ std::vector<CT> newCells;
+ newCells.reserve(oldCells.size());
+ for (const auto &cell : oldCells) {
+ CT nv = func.apply(cell);
+ newCells.push_back(nv);
+ }
+ return std::make_unique<DenseTensor<CT>>(newType, std::move(newCells));
+ }
+};
+
Tensor::UP
DenseTensorView::apply(const CellFunction &func) const
{
- Cells newCells(_cellsRef.size());
- auto itr = newCells.begin();
- for (const auto &cell : _cellsRef) {
- *itr = func.apply(cell);
- ++itr;
- }
- assert(itr == newCells.end());
- return std::make_unique<DenseTensor>(_typeRef, std::move(newCells));
+ return dispatch_1<CallApply>(_cellsRef, _typeRef, func);
}
bool
@@ -179,11 +223,20 @@ DenseTensorView::equals(const Tensor &arg) const
return false;
}
+struct CallClone {
+ template<class CT>
+ static Tensor::UP
+ call(const ConstArrayRef<CT> &cells, eval::ValueType newType)
+ {
+ std::vector<CT> newCells(cells.begin(), cells.end());
+ return std::make_unique<DenseTensor<CT>>(std::move(newType), std::move(newCells));
+ }
+};
+
Tensor::UP
DenseTensorView::clone() const
{
- return std::make_unique<DenseTensor>(_typeRef,
- Cells(_cellsRef.cbegin(), _cellsRef.cend()));
+ return dispatch_1<CallClone>(_cellsRef, _typeRef);
}
namespace {
@@ -277,12 +330,25 @@ DenseTensorView::reduce(join_fun_t op, const std::vector<vespalib::string> &dime
: reduce_all(op, dimensions);
}
+struct CallModify
+{
+ using join_fun_t = DenseTensorView::join_fun_t;
+
+ template <typename CT>
+ static std::unique_ptr<Tensor>
+ call(const ConstArrayRef<CT> &arr, join_fun_t op, const eval::ValueType &typeRef, const CellValues &cellValues)
+ {
+ std::vector newCells(arr.begin(), arr.end());
+ DenseTensorModify<CT> modifier(op, typeRef, std::move(newCells));
+ cellValues.accept(modifier);
+ return modifier.build();
+ }
+};
+
std::unique_ptr<Tensor>
DenseTensorView::modify(join_fun_t op, const CellValues &cellValues) const
{
- DenseTensorModify modifier(op, _typeRef, Cells(_cellsRef.cbegin(), _cellsRef.cend()));
- cellValues.accept(modifier);
- return modifier.build();
+ return dispatch_1<CallModify>(_cellsRef, op, _typeRef, cellValues);
}
std::unique_ptr<Tensor>
diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h
index 09b6b72375e..60f85c38659 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h
+++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h
@@ -2,6 +2,7 @@
#pragma once
+#include "typed_cells.h"
#include "dense_tensor_cells_iterator.h"
#include <vespa/eval/tensor/tensor.h>
@@ -14,12 +15,10 @@ namespace vespalib::tensor {
class DenseTensorView : public Tensor
{
public:
- using Cells = std::vector<double>;
- using CellsRef = ConstArrayRef<double>;
using CellsIterator = DenseTensorCellsIterator;
using Address = std::vector<eval::ValueType::Dimension::size_type>;
- DenseTensorView(const eval::ValueType &type_in, CellsRef cells_in)
+ DenseTensorView(const eval::ValueType &type_in, TypedCells cells_in)
: _typeRef(type_in),
_cellsRef(cells_in)
{}
@@ -29,7 +28,7 @@ public:
{}
const eval::ValueType &fast_type() const { return _typeRef; }
- const CellsRef &cellsRef() const { return _cellsRef; }
+ const TypedCells &cellsRef() const { return _cellsRef; }
bool operator==(const DenseTensorView &rhs) const;
CellsIterator cellsIterator() const { return CellsIterator(_typeRef, _cellsRef); }
@@ -46,14 +45,14 @@ public:
eval::TensorSpec toSpec() const override;
void accept(TensorVisitor &visitor) const override;
protected:
- void initCellsRef(CellsRef cells_in) {
+ void initCellsRef(TypedCells cells_in) {
_cellsRef = cells_in;
}
private:
Tensor::UP reduce_all(join_fun_t op, const std::vector<vespalib::string> &dimensions) const;
const eval::ValueType &_typeRef;
- CellsRef _cellsRef;
+ TypedCells _cellsRef;
};
}
diff --git a/eval/src/vespa/eval/tensor/dense/dense_xw_product_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_xw_product_function.cpp
index a3056311fab..b6ac87ce012 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_xw_product_function.cpp
+++ b/eval/src/vespa/eval/tensor/dense/dense_xw_product_function.cpp
@@ -12,7 +12,6 @@
namespace vespalib::tensor {
-using CellsRef = DenseTensorView::CellsRef;
using eval::ValueType;
using eval::TensorFunction;
using eval::as;
@@ -22,9 +21,11 @@ using namespace eval::operation;
namespace {
-CellsRef getCellsRef(const eval::Value &value) {
+XWInput getCellsRef(const eval::Value &value) {
const DenseTensorView &denseTensor = static_cast<const DenseTensorView &>(value);
- return denseTensor.cellsRef();
+ TypedCells ref = denseTensor.cellsRef();
+ assert(ref.type == CellType::DOUBLE);
+ return ref.typify<double>();
}
void multiDotProduct(const DenseXWProductFunction::Self &self,
@@ -62,8 +63,8 @@ template <bool commonDimensionInnermost>
void my_xw_product_op(eval::InterpretedFunction::State &state, uint64_t param) {
DenseXWProductFunction::Self *self = (DenseXWProductFunction::Self *)(param);
- CellsRef vectorCells = getCellsRef(state.peek(1));
- CellsRef matrixCells = getCellsRef(state.peek(0));
+ XWInput vectorCells = getCellsRef(state.peek(1));
+ XWInput matrixCells = getCellsRef(state.peek(0));
ArrayRef<double> outputCells = state.stash.create_array<double>(self->_resultSize);
@@ -72,7 +73,7 @@ void my_xw_product_op(eval::InterpretedFunction::State &state, uint64_t param) {
} else {
transposedProduct(*self, vectorCells, matrixCells, outputCells);
}
- state.pop_pop_push(state.stash.create<DenseTensorView>(self->_resultType, outputCells));
+ state.pop_pop_push(state.stash.create<DenseTensorView>(self->_resultType, TypedCells(outputCells)));
}
bool isConcreteDenseTensor(const ValueType &type, size_t d) {
diff --git a/eval/src/vespa/eval/tensor/dense/dense_xw_product_function.h b/eval/src/vespa/eval/tensor/dense/dense_xw_product_function.h
index a8ccdd331cf..9f1bc12b110 100644
--- a/eval/src/vespa/eval/tensor/dense/dense_xw_product_function.h
+++ b/eval/src/vespa/eval/tensor/dense/dense_xw_product_function.h
@@ -8,7 +8,7 @@
namespace vespalib::tensor {
-using XWInput = DenseTensorView::CellsRef;
+using XWInput = ConstArrayRef<double>;
using XWOutput = ArrayRef<double>;
/**
diff --git a/eval/src/vespa/eval/tensor/dense/direct_dense_tensor_builder.cpp b/eval/src/vespa/eval/tensor/dense/direct_dense_tensor_builder.cpp
deleted file mode 100644
index f800750bf8f..00000000000
--- a/eval/src/vespa/eval/tensor/dense/direct_dense_tensor_builder.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "direct_dense_tensor_builder.h"
-
-namespace vespalib::tensor {
-
-using Address = DirectDenseTensorBuilder::Address;
-using eval::ValueType;
-
-namespace {
-
-size_t
-calculateCellsSize(const ValueType &type)
-{
- size_t cellsSize = 1;
- for (const auto &dim : type.dimensions()) {
- cellsSize *= dim.size;
- }
- return cellsSize;
-}
-
-}
-
-DirectDenseTensorBuilder::~DirectDenseTensorBuilder() = default;
-
-DirectDenseTensorBuilder::DirectDenseTensorBuilder(const ValueType &type_in)
- : _type(type_in),
- _cells(calculateCellsSize(_type))
-{
-}
-
-Tensor::UP
-DirectDenseTensorBuilder::build()
-{
- return std::make_unique<DenseTensor>(std::move(_type), std::move(_cells));
-}
-
-}
-
diff --git a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp
index 79a8b994480..08abc391179 100644
--- a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp
+++ b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.cpp
@@ -21,12 +21,12 @@ MutableDenseTensorView::MutableValueType::MutableValueType(ValueType type_in)
MutableDenseTensorView::MutableValueType::~MutableValueType() = default;
MutableDenseTensorView::MutableDenseTensorView(ValueType type_in)
- : DenseTensorView(_concreteType._type, CellsRef()),
+ : DenseTensorView(_concreteType._type),
_concreteType(type_in)
{
}
-MutableDenseTensorView::MutableDenseTensorView(ValueType type_in, CellsRef cells_in)
+MutableDenseTensorView::MutableDenseTensorView(ValueType type_in, TypedCells cells_in)
: DenseTensorView(_concreteType._type, cells_in),
_concreteType(type_in)
{
diff --git a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h
index 260e71b6f76..d71903d6c47 100644
--- a/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h
+++ b/eval/src/vespa/eval/tensor/dense/mutable_dense_tensor_view.h
@@ -42,8 +42,8 @@ private:
public:
MutableDenseTensorView(eval::ValueType type_in);
- MutableDenseTensorView(eval::ValueType type_in, CellsRef cells_in);
- void setCells(CellsRef cells_in) {
+ MutableDenseTensorView(eval::ValueType type_in, TypedCells cells_in);
+ void setCells(TypedCells cells_in) {
initCellsRef(cells_in);
}
void setUnboundDimensions(const uint32_t *unboundDimSizeBegin, const uint32_t *unboundDimSizeEnd) {
diff --git a/eval/src/vespa/eval/tensor/dense/typed_cells.cpp b/eval/src/vespa/eval/tensor/dense/typed_cells.cpp
new file mode 100644
index 00000000000..e56325bffd2
--- /dev/null
+++ b/eval/src/vespa/eval/tensor/dense/typed_cells.cpp
@@ -0,0 +1,7 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "typed_cells.h"
+
+namespace vespalib::tensor {
+
+} // namespace
diff --git a/eval/src/vespa/eval/tensor/dense/typed_cells.h b/eval/src/vespa/eval/tensor/dense/typed_cells.h
new file mode 100644
index 00000000000..d1b6058bfbe
--- /dev/null
+++ b/eval/src/vespa/eval/tensor/dense/typed_cells.h
@@ -0,0 +1,96 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <assert.h>
+#include <vespa/vespalib/util/arrayref.h>
+#include <vespa/eval/eval/value_type.h>
+
+namespace vespalib::tensor {
+
+// Low-level typed cells reference
+
+using CellType = vespalib::eval::ValueType::CellType;
+
+
+template<typename LCT, typename RCT> struct OutputCellType;
+template<> struct OutputCellType<double, double> {
+ typedef double output_type;
+ static constexpr CellType output_cell_type() { return CellType::DOUBLE; };
+};
+template<> struct OutputCellType<float, double> {
+ typedef double output_type;
+ static constexpr CellType output_cell_type() { return CellType::DOUBLE; };
+};
+template<> struct OutputCellType<double, float> {
+ typedef double output_type;
+ static constexpr CellType output_cell_type() { return CellType::DOUBLE; };
+};
+template<> struct OutputCellType<float, float> {
+ typedef float output_type;
+ static constexpr CellType output_cell_type() { return CellType::FLOAT; };
+};
+
+struct TypedCells {
+ const void *data;
+ CellType type;
+ size_t size:56;
+
+ explicit TypedCells(ConstArrayRef<double> cells) : data(cells.begin()), type(CellType::DOUBLE), size(cells.size()) {}
+ explicit TypedCells(ConstArrayRef<float> cells) : data(cells.begin()), type(CellType::FLOAT), size(cells.size()) {}
+
+ TypedCells() : data(nullptr), type(CellType::DOUBLE), size(0) {}
+ TypedCells(const void *dp, CellType ct, size_t sz) : data(dp), type(ct), size(sz) {}
+
+ template <typename T> bool check_type() const { return vespalib::eval::check_cell_type<T>(type); }
+ template <typename T> ConstArrayRef<T> typify() const {
+ assert(check_type<T>());
+ return ConstArrayRef<T>((const T *)data, size);
+ }
+ template <typename T> ConstArrayRef<T> unsafe_typify() const {
+ return ConstArrayRef<T>((const T *)data, size);
+ }
+
+ double get(size_t idx) const {
+ if (type == CellType::DOUBLE) {
+ const double *p = (const double *)data;
+ return p[idx];
+ }
+ if (type == CellType::FLOAT) {
+ const float *p = (const float *)data;
+ return p[idx];
+ }
+ abort();
+ }
+
+ TypedCells & operator= (const TypedCells &other) = default;
+};
+
+template <typename TGT, typename... Args>
+auto dispatch_0(CellType ct, Args &&...args) {
+ switch (ct) {
+ case CellType::DOUBLE: return TGT::template call<double>(std::forward<Args>(args)...);
+ case CellType::FLOAT: return TGT::template call<float>(std::forward<Args>(args)...);
+ }
+ abort();
+}
+
+template <typename TGT, typename... Args>
+auto dispatch_1(const TypedCells &a, Args &&...args) {
+ switch (a.type) {
+ case CellType::DOUBLE: return TGT::call(a.unsafe_typify<double>(), std::forward<Args>(args)...);
+ case CellType::FLOAT: return TGT::call(a.unsafe_typify<float>(), std::forward<Args>(args)...);
+ }
+ abort();
+}
+
+template <typename TGT, typename A1, typename... Args>
+auto dispatch_2(A1 &&a, const TypedCells &b, Args &&...args) {
+ switch (b.type) {
+ case CellType::DOUBLE: return dispatch_1<TGT>(std::forward<A1>(a), b.unsafe_typify<double>(), std::forward<Args>(args)...);
+ case CellType::FLOAT: return dispatch_1<TGT>(std::forward<A1>(a), b.unsafe_typify<float>(), std::forward<Args>(args)...);
+ }
+ abort();
+}
+
+} // namespace
diff --git a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp b/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp
new file mode 100644
index 00000000000..3e7d234fd54
--- /dev/null
+++ b/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp
@@ -0,0 +1,45 @@
+
+
+#include "typed_dense_tensor_builder.h"
+
+namespace vespalib::tensor {
+
+using Address = DenseTensorView::Address;
+using eval::ValueType;
+
+namespace {
+
+size_t
+calculateCellsSize(const ValueType &type)
+{
+ size_t cellsSize = 1;
+ for (const auto &dim : type.dimensions()) {
+ cellsSize *= dim.size;
+ }
+ return cellsSize;
+}
+
+} // namespace
+
+template <typename CT>
+TypedDenseTensorBuilder<CT>::~TypedDenseTensorBuilder() = default;
+
+template <typename CT>
+TypedDenseTensorBuilder<CT>::TypedDenseTensorBuilder(const ValueType &type_in)
+ : _type(type_in),
+ _cells(calculateCellsSize(_type))
+{
+ assert(vespalib::eval::check_cell_type<CT>(_type.cell_type()));
+}
+
+template <typename CT>
+Tensor::UP
+TypedDenseTensorBuilder<CT>::build()
+{
+ return std::make_unique<DenseTensor<CT>>(std::move(_type), std::move(_cells));
+}
+
+template class TypedDenseTensorBuilder<double>;
+template class TypedDenseTensorBuilder<float>;
+
+} // namespace
diff --git a/eval/src/vespa/eval/tensor/dense/direct_dense_tensor_builder.h b/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h
index 935b5c20373..770ea4ae5ea 100644
--- a/eval/src/vespa/eval/tensor/dense/direct_dense_tensor_builder.h
+++ b/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h
@@ -9,15 +9,14 @@ namespace vespalib::tensor {
/**
* Class for building a dense tensor by inserting cell values directly into underlying array of cells.
*/
-class DirectDenseTensorBuilder
+template <typename CT>
+class TypedDenseTensorBuilder
{
public:
- using Cells = DenseTensor::Cells;
- using Address = DenseTensor::Address;
-
+ using Address = DenseTensorView::Address;
private:
eval::ValueType _type;
- Cells _cells;
+ std::vector<CT> _cells;
static size_t calculateCellAddress(const Address &address, const eval::ValueType &type) {
size_t result = 0;
@@ -28,16 +27,15 @@ private:
return result;
}
public:
- DirectDenseTensorBuilder(const eval::ValueType &type_in);
- ~DirectDenseTensorBuilder();
- void insertCell(const Address &address, double cellValue) {
+ TypedDenseTensorBuilder(const eval::ValueType &type_in);
+ ~TypedDenseTensorBuilder();
+ void insertCell(const Address &address, CT cellValue) {
insertCell(calculateCellAddress(address, _type), cellValue);
}
- void insertCell(size_t index, double cellValue) {
+ void insertCell(size_t index, CT cellValue) {
_cells[index] = cellValue;
}
Tensor::UP build();
};
}
-
diff --git a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp b/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp
index 445b08ab114..4694aea717d 100644
--- a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp
+++ b/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp
@@ -9,7 +9,6 @@
namespace vespalib::tensor {
-using CellsRef = DenseTensorView::CellsRef;
using eval::Value;
using eval::ValueType;
using eval::TensorFunction;
@@ -20,14 +19,25 @@ using namespace eval::operation;
namespace {
+struct CallVectorFromDoubles {
+ template <typename CT>
+ static TypedCells
+ call(eval::InterpretedFunction::State &state, size_t numCells) {
+ ArrayRef<CT> outputCells = state.stash.create_array<CT>(numCells);
+ for (size_t i = numCells; i-- > 0; ) {
+ outputCells[i] = (CT) state.peek(0).as_double();
+ state.stack.pop_back();
+ }
+ return TypedCells(outputCells);
+ }
+};
+
void my_vector_from_doubles_op(eval::InterpretedFunction::State &state, uint64_t param) {
const auto *self = (const VectorFromDoublesFunction::Self *)(param);
- ArrayRef<double> outputCells = state.stash.create_array<double>(self->resultSize);
- for (size_t i = self->resultSize; i-- > 0; ) {
- outputCells[i] = state.peek(0).as_double();
- state.stack.pop_back();
- }
- const Value &result = state.stash.create<DenseTensorView>(self->resultType, outputCells);
+ CellType ct = self->resultType.cell_type();
+ size_t numCells = self->resultSize;
+ TypedCells cells = dispatch_0<CallVectorFromDoubles>(ct, state, numCells);
+ const Value &result = state.stash.create<DenseTensorView>(self->resultType, cells);
state.stack.push_back(result);
}
diff --git a/eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp b/eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp
index 677fb40b0f4..493e4af3caf 100644
--- a/eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp
+++ b/eval/src/vespa/eval/tensor/serialization/dense_binary_format.cpp
@@ -29,9 +29,10 @@ size_t encodeDimensions(nbostream &stream, const eval::ValueType & type) {
}
template<typename T>
-void encodeCells(nbostream &stream, DenseTensorView::CellsRef cells) {
- for (const auto &value : cells) {
- stream << static_cast<T>(value);
+void encodeCells(nbostream &stream, TypedCells cells) {
+ auto arr = cells.typify<T>();
+ for (const auto &value : arr) {
+ stream << value;
}
}
@@ -76,8 +77,8 @@ void
DenseBinaryFormat::serialize(nbostream &stream, const DenseTensorView &tensor)
{
size_t cellsSize = encodeDimensions(stream, tensor.fast_type());
- DenseTensorView::CellsRef cells = tensor.cellsRef();
- assert(cells.size() == cellsSize);
+ TypedCells cells = tensor.cellsRef();
+ assert(cells.size == cellsSize);
switch (tensor.fast_type().cell_type()) {
case CellType::DOUBLE:
encodeCells<double>(stream, cells);
@@ -88,15 +89,24 @@ DenseBinaryFormat::serialize(nbostream &stream, const DenseTensorView &tensor)
}
}
-std::unique_ptr<DenseTensor>
+struct CallDecodeCells {
+ template <typename CT>
+ static std::unique_ptr<DenseTensorView>
+ call(nbostream &stream, size_t numCells, ValueType &&newType) {
+ std::vector<CT> newCells;
+ newCells.reserve(numCells);
+ decodeCells<CT>(stream, numCells, newCells);
+ return std::make_unique<DenseTensor<CT>>(std::move(newType), std::move(newCells));
+ }
+};
+
+std::unique_ptr<DenseTensorView>
DenseBinaryFormat::deserialize(nbostream &stream, CellType cell_type)
{
std::vector<Dimension> dimensions;
- size_t cellsSize = decodeDimensions(stream,dimensions);
- DenseTensor::Cells cells;
- cells.reserve(cellsSize);
- decodeCells(cell_type, stream, cellsSize, cells);
- return std::make_unique<DenseTensor>(ValueType::tensor_type(std::move(dimensions), cell_type), std::move(cells));
+ size_t numCells = decodeDimensions(stream, dimensions);
+ ValueType newType = ValueType::tensor_type(std::move(dimensions), cell_type);
+ return dispatch_0<CallDecodeCells>(cell_type, stream, numCells, std::move(newType));
}
template <typename T>
@@ -104,7 +114,7 @@ void
DenseBinaryFormat::deserializeCellsOnly(nbostream &stream, std::vector<T> &cells, CellType cell_type)
{
std::vector<Dimension> dimensions;
- size_t cellsSize = decodeDimensions(stream,dimensions);
+ size_t cellsSize = decodeDimensions(stream, dimensions);
cells.clear();
cells.reserve(cellsSize);
decodeCells(cell_type, stream, cellsSize, cells);
diff --git a/eval/src/vespa/eval/tensor/serialization/dense_binary_format.h b/eval/src/vespa/eval/tensor/serialization/dense_binary_format.h
index 9e860b3c1e4..21618dcb6ce 100644
--- a/eval/src/vespa/eval/tensor/serialization/dense_binary_format.h
+++ b/eval/src/vespa/eval/tensor/serialization/dense_binary_format.h
@@ -10,7 +10,6 @@ namespace vespalib { class nbostream; }
namespace vespalib::tensor {
-class DenseTensor;
class DenseTensorView;
/**
@@ -22,7 +21,7 @@ public:
using CellType = eval::ValueType::CellType;
static void serialize(nbostream &stream, const DenseTensorView &tensor);
- static std::unique_ptr<DenseTensor> deserialize(nbostream &stream, CellType cell_type);
+ static std::unique_ptr<DenseTensorView> deserialize(nbostream &stream, CellType cell_type);
// This is a temporary method untill we get full support for typed tensors
template <typename T>
diff --git a/eval/src/vespa/eval/tensor/tensor_mapper.cpp b/eval/src/vespa/eval/tensor/tensor_mapper.cpp
deleted file mode 100644
index 6f2b094af9e..00000000000
--- a/eval/src/vespa/eval/tensor/tensor_mapper.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "tensor_mapper.h"
-#include "tensor.h"
-#include "tensor_visitor.h"
-#include "tensor_address_element_iterator.h"
-#include "wrapped_simple_tensor.h"
-#include <vespa/eval/tensor/sparse/direct_sparse_tensor_builder.h>
-#include <vespa/eval/tensor/dense/dense_tensor.h>
-#include <vespa/eval/tensor/dense/dense_tensor_address_mapper.h>
-#include <vespa/vespalib/stllike/hash_map.hpp>
-#include <limits>
-
-using vespalib::eval::ValueType;
-using vespalib::eval::TensorSpec;
-
-namespace vespalib::tensor {
-
-namespace {
-
-//-----------------------------------------------------------------------------
-
-template <class TensorT>
-class SparseTensorMapper : public TensorVisitor
-{
- using Builder = DirectSparseTensorBuilder;
- using AddressBuilderType = typename Builder::AddressBuilderType;
-
- Builder _builder;
- AddressBuilderType _addressBuilder;
-
- void mapAddress(const TensorAddress &address);
- virtual void visit(const TensorAddress &address, double value) override;
-
- SparseTensorMapper(const ValueType &type);
-
- ~SparseTensorMapper();
-
- std::unique_ptr<Tensor> build();
-public:
- static std::unique_ptr<Tensor>
- map(const Tensor &tensor, const ValueType &type);
-};
-
-template <class TensorT>
-SparseTensorMapper<TensorT>::
-SparseTensorMapper(const ValueType &type)
- : TensorVisitor(),
- _builder(type),
- _addressBuilder()
-{
-}
-
-template <class TensorT>
-SparseTensorMapper<TensorT>::~SparseTensorMapper() = default;
-
-template <class TensorT>
-std::unique_ptr<Tensor>
-SparseTensorMapper<TensorT>::build()
-{
- return _builder.build();
-}
-
-template <>
-void
-SparseTensorMapper<SparseTensor>::
-mapAddress(const TensorAddress &address)
-{
- _addressBuilder.clear();
- TensorAddressElementIterator<TensorAddress> addressIterator(address);
- for (const auto &dimension : _builder.fast_type().dimensions()) {
- if (addressIterator.skipToDimension(dimension.name)) {
- _addressBuilder.add(addressIterator.label());
- addressIterator.next();
- } else {
- // output dimension not in input
- _addressBuilder.addUndefined();
- }
- }
-}
-
-template <class TensorT>
-void
-SparseTensorMapper<TensorT>::visit(const TensorAddress &address, double value)
-{
- mapAddress(address);
- _builder.insertCell(_addressBuilder, value,
- [](double oldValue, double newValue)
- { return oldValue + newValue; });
-}
-
-template <class TensorT>
-std::unique_ptr<Tensor>
-SparseTensorMapper<TensorT>::map(const Tensor &tensor,
- const ValueType &type)
-{
- SparseTensorMapper<TensorT> mapper(type);
- tensor.accept(mapper);
- return mapper.build();
-}
-
-//-----------------------------------------------------------------------------
-
-class DenseTensorMapper : public TensorVisitor
-{
- ValueType _type;
- DenseTensor::Cells _cells;
-
- uint32_t mapAddressToIndex(const TensorAddress &address);
- virtual void visit(const TensorAddress &address, double value) override;
-
- DenseTensorMapper(const ValueType &type);
- ~DenseTensorMapper();
-
- std::unique_ptr<Tensor> build();
-public:
- static std::unique_ptr<Tensor>
- map(const Tensor &tensor, const ValueType &type);
-};
-
-DenseTensorMapper::DenseTensorMapper(const ValueType &type)
- : _type(type),
- _cells()
-{
- size_t size = 1;
- for (const auto &dimension : type.dimensions()) {
- size *= dimension.size;
- }
- _cells.resize(size);
-}
-
-DenseTensorMapper::~DenseTensorMapper()
-{
-}
-
-std::unique_ptr<Tensor>
-DenseTensorMapper::build()
-{
- return std::make_unique<DenseTensor>(std::move(_type),
- std::move(_cells));
-}
-
-void
-DenseTensorMapper::visit(const TensorAddress &address, double value)
-{
- uint32_t idx = DenseTensorAddressMapper::mapAddressToIndex(address, _type);
- if (idx != DenseTensorAddressMapper::BAD_ADDRESS) {
- assert(idx < _cells.size());
- _cells[idx] += value;
- }
-}
-
-std::unique_ptr<Tensor>
-DenseTensorMapper::map(const Tensor &tensor, const ValueType &type)
-{
- DenseTensorMapper mapper(type);
- tensor.accept(mapper);
- return mapper.build();
-}
-
-//-----------------------------------------------------------------------------
-
-class WrappedTensorMapper : public TensorVisitor
-{
- using Label = TensorSpec::Label;
-
- ValueType _type;
- TensorSpec _spec;
-
- WrappedTensorMapper(const ValueType &type)
- : _type(type), _spec(type.to_spec()) {}
- ~WrappedTensorMapper() {}
-
- void visit(const TensorAddress &address, double value) override;
-
- std::unique_ptr<Tensor> build() {
- auto tensor = eval::SimpleTensor::create(_spec);
- return std::make_unique<WrappedSimpleTensor>(std::move(tensor));
- }
-
-public:
- static std::unique_ptr<Tensor>
- map(const Tensor &tensor, const ValueType &type);
-};
-
-void
-WrappedTensorMapper::visit(const TensorAddress &address, double value)
-{
- TensorSpec::Address addr;
- TensorAddressElementIterator<TensorAddress> addressIterator(address);
- for (const auto &dimension: _type.dimensions()) {
- if (addressIterator.skipToDimension(dimension.name)) {
- if (dimension.is_indexed()) {
- uint32_t label = DenseTensorAddressMapper::mapLabelToNumber(addressIterator.label());
- if ((label == DenseTensorAddressMapper::BAD_LABEL) || (label >= dimension.size)) {
- return; // bad address; ignore cell
- }
- addr.emplace(dimension.name, label);
- } else {
- addr.emplace(dimension.name, addressIterator.label());
- }
- addressIterator.next();
- } else {
- if (dimension.is_indexed()) {
- addr.emplace(dimension.name, size_t(0));
- } else {
- addr.emplace(dimension.name, vespalib::string());
- }
- }
- }
- _spec.add(addr, value);
-}
-
-std::unique_ptr<Tensor>
-WrappedTensorMapper::map(const Tensor &tensor, const ValueType &type)
-{
- WrappedTensorMapper mapper(type);
- tensor.accept(mapper);
- return mapper.build();
-}
-
-//-----------------------------------------------------------------------------
-
-} // namespace vespalib::tensor::<anonymous>
-
-TensorMapper::TensorMapper(const ValueType &type)
- : _type(type)
-{
-}
-
-TensorMapper::~TensorMapper()
-{
-}
-
-template <typename TensorT>
-std::unique_ptr<Tensor>
-TensorMapper::mapToSparse(const Tensor &tensor, const ValueType &type)
-{
- assert(type.is_sparse());
- return SparseTensorMapper<TensorT>::map(tensor, type);
-}
-
-std::unique_ptr<Tensor>
-TensorMapper::mapToDense(const Tensor &tensor, const ValueType &type)
-{
- assert(type.is_dense());
- return DenseTensorMapper::map(tensor, type);
-}
-
-std::unique_ptr<Tensor>
-TensorMapper::mapToWrapped(const Tensor &tensor, const ValueType &type)
-{
- assert(!type.dimensions().empty());
- return WrappedTensorMapper::map(tensor, type);
-}
-
-std::unique_ptr<Tensor>
-TensorMapper::map(const Tensor &tensor) const
-{
- if (_type.is_sparse()) {
- return mapToSparse<SparseTensor>(tensor, _type);
- } else if (_type.is_dense()) {
- return mapToDense(tensor, _type);
- } else {
- return mapToWrapped(tensor, _type);
- }
-}
-
-template
-std::unique_ptr<Tensor>
-TensorMapper::mapToSparse<SparseTensor>(const Tensor &tensor,
- const ValueType &type);
-
-}
diff --git a/eval/src/vespa/eval/tensor/tensor_mapper.h b/eval/src/vespa/eval/tensor/tensor_mapper.h
deleted file mode 100644
index 95c6cce8fc6..00000000000
--- a/eval/src/vespa/eval/tensor/tensor_mapper.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/eval/eval/value_type.h>
-
-namespace vespalib::tensor {
-
-class Tensor;
-
-/**
- * Class to map a tensor to a given tensor type. Dimensions in input
- * tensor not present in tensor type are ignored. Dimensions in tensor
- * type not present in input tensor gets default label (undefined
- * (empty string) for sparse tensors, 0 for dense tensors). Values are
- * accumulated for identical mapped addresses.
- *
- * Dense tensor type has further restrictions: label must contain only
- * numerical digits (0-9). Empty string equals 0. If the label is
- * parsed to a value outside the dimension range or the parsing fails,
- * then the cell ((address, value) pair) is ignored.
- */
-class TensorMapper
-{
- eval::ValueType _type;
-public:
- TensorMapper(const eval::ValueType &type);
- ~TensorMapper();
-
- template <typename TensorT>
- static std::unique_ptr<Tensor>
- mapToSparse(const Tensor &tensor, const eval::ValueType &type);
-
- static std::unique_ptr<Tensor>
- mapToDense(const Tensor &tensor, const eval::ValueType &type);
-
- static std::unique_ptr<Tensor>
- mapToWrapped(const Tensor &tensor, const eval::ValueType &type);
-
- std::unique_ptr<Tensor> map(const Tensor &tensor) const;
-};
-
-
-}