From f21b553eb7903cf4a2d7a01fc222c9dfee8a3253 Mon Sep 17 00:00:00 2001 From: Geir Storli Date: Fri, 8 Feb 2019 12:09:56 +0000 Subject: Implement add() function on vespalib::tensor::Tensor for adding a set of cells to the tensor. Currently only supported for sparse tensor. --- .../tensor/tensor_add_operation/CMakeLists.txt | 8 ++++ .../tensor_add_operation_test.cpp | 46 ++++++++++++++++++++++ .../vespa/eval/tensor/dense/dense_tensor_view.cpp | 9 +++++ .../vespa/eval/tensor/dense/dense_tensor_view.h | 1 + eval/src/vespa/eval/tensor/sparse/CMakeLists.txt | 2 + .../src/vespa/eval/tensor/sparse/sparse_tensor.cpp | 22 +++++++++-- eval/src/vespa/eval/tensor/sparse/sparse_tensor.h | 1 + .../vespa/eval/tensor/sparse/sparse_tensor_add.cpp | 33 ++++++++++++++++ .../vespa/eval/tensor/sparse/sparse_tensor_add.h | 32 +++++++++++++++ .../sparse/sparse_tensor_address_builder.cpp | 29 ++++++++++++++ .../tensor/sparse/sparse_tensor_address_builder.h | 7 +++- .../eval/tensor/sparse/sparse_tensor_modify.cpp | 11 +----- eval/src/vespa/eval/tensor/tensor.h | 11 +++++- .../eval/tensor/tensor_address_element_iterator.h | 8 ++-- .../vespa/eval/tensor/wrapped_simple_tensor.cpp | 6 +++ eval/src/vespa/eval/tensor/wrapped_simple_tensor.h | 1 + 16 files changed, 208 insertions(+), 19 deletions(-) create mode 100644 eval/src/tests/tensor/tensor_add_operation/CMakeLists.txt create mode 100644 eval/src/tests/tensor/tensor_add_operation/tensor_add_operation_test.cpp create mode 100644 eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.cpp create mode 100644 eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.h create mode 100644 eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.cpp (limited to 'eval/src') diff --git a/eval/src/tests/tensor/tensor_add_operation/CMakeLists.txt b/eval/src/tests/tensor/tensor_add_operation/CMakeLists.txt new file mode 100644 index 00000000000..6c19b13db7e --- /dev/null +++ b/eval/src/tests/tensor/tensor_add_operation/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(eval_tensor_add_operation_test_app TEST + SOURCES + tensor_add_operation_test.cpp + DEPENDS + vespaeval +) +vespa_add_test(NAME eval_tensor_add_operation_test_app COMMAND eval_tensor_add_operation_test_app) diff --git a/eval/src/tests/tensor/tensor_add_operation/tensor_add_operation_test.cpp b/eval/src/tests/tensor/tensor_add_operation/tensor_add_operation_test.cpp new file mode 100644 index 00000000000..5d017fdcd5c --- /dev/null +++ b/eval/src/tests/tensor/tensor_add_operation/tensor_add_operation_test.cpp @@ -0,0 +1,46 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include +#include +#include +#include + +using vespalib::eval::Value; +using vespalib::eval::TensorSpec; +using namespace vespalib::tensor; + +std::unique_ptr +makeTensor(const TensorSpec &spec) +{ + auto value = DefaultTensorEngine::ref().from_spec(spec); + const auto *tensor = dynamic_cast(value->as_tensor()); + ASSERT_TRUE(tensor); + value.release(); + return std::unique_ptr(const_cast(tensor)); +} + +void +assertAdd(const TensorSpec &source, const TensorSpec &arg, const TensorSpec &expected) +{ + auto sourceTensor = makeTensor(source); + auto argTensor = makeTensor(arg); + auto resultTensor = sourceTensor->add(*argTensor); + auto actual = resultTensor->toSpec(); + EXPECT_EQUAL(actual, expected); +} + +TEST("require that cells can be added to a sparse tensor") +{ + assertAdd(TensorSpec("tensor(x{},y{})") + .add({{"x","a"},{"y","b"}}, 2) + .add({{"x","c"},{"y","d"}}, 3), + TensorSpec("tensor(x{},y{})") + .add({{"x","a"},{"y","b"}}, 5) + .add({{"x","e"},{"y","f"}}, 7), + TensorSpec("tensor(x{},y{})") + .add({{"x","a"},{"y","b"}}, 5) + .add({{"x","c"},{"y","d"}}, 3) + .add({{"x","e"},{"y","f"}}, 7)); +} + +TEST_MAIN() { TEST_RUN_ALL(); } 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 f758b0ec915..6243f79a971 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.cpp @@ -13,6 +13,9 @@ #include #include +#include +LOG_SETUP(".eval.tensor.dense.dense_tensor_view"); + using vespalib::eval::TensorSpec; namespace vespalib::tensor { @@ -290,4 +293,10 @@ DenseTensorView::modify(join_fun_t op, const CellValues &cellValues) const return modifier.build(); } +std::unique_ptr +DenseTensorView::add(const Tensor &) const +{ + LOG_ABORT("should not be reached"); +} + } 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 5aedcf6fb8d..f470e9d374f 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h +++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_view.h @@ -54,6 +54,7 @@ public: Tensor::UP join(join_fun_t function, const Tensor &arg) const override; Tensor::UP reduce(join_fun_t op, const std::vector &dimensions) const override; std::unique_ptr modify(join_fun_t op, const CellValues &cellValues) const override; + std::unique_ptr add(const Tensor &arg) const override; bool equals(const Tensor &arg) const override; Tensor::UP clone() const override; eval::TensorSpec toSpec() const override; diff --git a/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt b/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt index 57855dc7eaa..d50c6d5db10 100644 --- a/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt +++ b/eval/src/vespa/eval/tensor/sparse/CMakeLists.txt @@ -2,6 +2,8 @@ vespa_add_library(eval_tensor_sparse OBJECT SOURCES sparse_tensor.cpp + sparse_tensor_add.cpp + sparse_tensor_address_builder.cpp sparse_tensor_address_combiner.cpp sparse_tensor_address_padder.cpp sparse_tensor_address_reducer.cpp diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp index dd2befd4df8..e3ee9593d80 100644 --- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.cpp @@ -1,16 +1,17 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "sparse_tensor.h" +#include "sparse_tensor_add.h" #include "sparse_tensor_address_builder.h" -#include "sparse_tensor_match.h" #include "sparse_tensor_apply.hpp" -#include "sparse_tensor_reduce.hpp" +#include "sparse_tensor_match.h" #include "sparse_tensor_modify.h" +#include "sparse_tensor_reduce.hpp" +#include #include #include #include #include -#include #include #include #include @@ -199,6 +200,21 @@ SparseTensor::modify(join_fun_t op, const CellValues &cellValues) const return modifier.build(); } +std::unique_ptr +SparseTensor::add(const Tensor &arg) const +{ + const SparseTensor *rhs = dynamic_cast(&arg); + if (!rhs) { + return Tensor::UP(); + } + Cells cells; + Stash stash; + copyCells(cells, _cells, stash); + SparseTensorAdd adder(_type, std::move(cells), std::move(stash)); + rhs->accept(adder); + return adder.build(); +} + } VESPALIB_HASH_MAP_INSTANTIATE_H_E_M(vespalib::tensor::SparseTensorAddressRef, double, vespalib::hash, diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h index 36a0c246d25..107cba7a673 100644 --- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor.h @@ -46,6 +46,7 @@ public: Tensor::UP join(join_fun_t function, const Tensor &arg) const override; Tensor::UP reduce(join_fun_t op, const std::vector &dimensions) const override; std::unique_ptr modify(join_fun_t op, const CellValues &cellValues) const override; + std::unique_ptr add(const Tensor &arg) const override; bool equals(const Tensor &arg) const override; Tensor::UP clone() const override; eval::TensorSpec toSpec() const override; diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.cpp new file mode 100644 index 00000000000..4503787e00e --- /dev/null +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.cpp @@ -0,0 +1,33 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "sparse_tensor_add.h" + +namespace vespalib::tensor { + +SparseTensorAdd::SparseTensorAdd(const eval::ValueType &type, Cells &&cells, Stash &&stash) + : _type(type), + _cells(std::move(cells)), + _stash(std::move(stash)), + _addressBuilder() +{ +} + +SparseTensorAdd::~SparseTensorAdd() = default; + +void +SparseTensorAdd::visit(const TensorAddress &address, double value) +{ + _addressBuilder.populate(_type, address); + auto addressRef = _addressBuilder.getAddressRef(); + // Make a persistent copy of the tensor address (owned by _stash) as the cell to insert might not already exist. + auto persistentAddress = SparseTensorAddressRef(addressRef, _stash); + _cells[persistentAddress] = value; +} + +std::unique_ptr +SparseTensorAdd::build() +{ + return std::make_unique(std::move(_type), std::move(_cells), std::move(_stash)); +} + +} diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.h new file mode 100644 index 00000000000..8adc95adf35 --- /dev/null +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_add.h @@ -0,0 +1,32 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include "sparse_tensor.h" +#include "sparse_tensor_address_builder.h" +#include + +namespace vespalib::tensor { + +/** + * This class handles a tensor add operation on a sparse tensor. + * + * Creates a new tensor by adding the cells of the argument tensor to this tensor. + * Existing cell values are overwritten. + */ +class SparseTensorAdd : public TensorVisitor +{ + using Cells = SparseTensor::Cells; + eval::ValueType _type; + Cells _cells; + Stash _stash; + SparseTensorAddressBuilder _addressBuilder; + +public: + SparseTensorAdd(const eval::ValueType &type, Cells &&cells, Stash &&stash); + ~SparseTensorAdd(); + void visit(const TensorAddress &address, double value) override; + std::unique_ptr build(); +}; + +} diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.cpp new file mode 100644 index 00000000000..3eb7d64f060 --- /dev/null +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.cpp @@ -0,0 +1,29 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "sparse_tensor_address_builder.h" +#include +#include +#include + +namespace vespalib::tensor { + +SparseTensorAddressBuilder::SparseTensorAddressBuilder() + : _address() +{ +} + +void +SparseTensorAddressBuilder::populate(const eval::ValueType &type, const TensorAddress &address) +{ + clear(); + TensorAddressElementIterator itr(address); + for (const auto &dimension : type.dimensions()) { + if (itr.skipToDimension(dimension.name)) { + add(itr.label()); + } else { + addUndefined(); + } + } +} + +} diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.h index f74ce257b31..a6f05bb70fb 100644 --- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.h +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_address_builder.h @@ -5,8 +5,12 @@ #include "sparse_tensor_address_ref.h" #include +namespace vespalib::eval { class ValueType; } + namespace vespalib::tensor { +class TensorAddress; + /** * A writer to serialize tensor addresses into a compact representation. @@ -32,7 +36,7 @@ protected: } } public: - SparseTensorAddressBuilder() : _address() {} + SparseTensorAddressBuilder(); void add(vespalib::stringref label) { ensure_room(label.size()+1); append(label); @@ -43,6 +47,7 @@ public: return SparseTensorAddressRef(&_address[0], _address.size()); } bool empty() const { return _address.empty(); } + void populate(const eval::ValueType &type, const TensorAddress &address); }; } diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.cpp b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.cpp index 91d0fa3fcdd..0ab8352bfbb 100644 --- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.cpp +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_modify.cpp @@ -19,16 +19,7 @@ SparseTensorModify::~SparseTensorModify() = default; void SparseTensorModify::visit(const TensorAddress &address, double value) { - TensorAddressElementIterator addressElementIterator(address); - - _addressBuilder.clear(); - for (const auto &dimension : _type.dimensions()) { - if (addressElementIterator.skipToDimension(dimension.name)) { - _addressBuilder.add(addressElementIterator.label()); - } else { - _addressBuilder.addUndefined(); - } - } + _addressBuilder.populate(_type, address); auto addressRef = _addressBuilder.getAddressRef(); auto cellItr = _cells.find(addressRef); if (cellItr != _cells.end()) { diff --git a/eval/src/vespa/eval/tensor/tensor.h b/eval/src/vespa/eval/tensor/tensor.h index 8e10af04b18..cdb9d90d3a3 100644 --- a/eval/src/vespa/eval/tensor/tensor.h +++ b/eval/src/vespa/eval/tensor/tensor.h @@ -23,8 +23,9 @@ class CellValues; * Each cell is identified by its address, which consists of a set of dimension -> label pairs, * where both dimension and label is a string on the form of an identifier or integer. */ -struct Tensor : public eval::Tensor +class Tensor : public eval::Tensor { +public: typedef std::unique_ptr UP; typedef std::reference_wrapper CREF; using join_fun_t = double (*)(double, double); @@ -34,12 +35,20 @@ struct Tensor : public eval::Tensor virtual Tensor::UP apply(const CellFunction &func) const = 0; virtual Tensor::UP join(join_fun_t function, const Tensor &arg) const = 0; virtual Tensor::UP reduce(join_fun_t op, const std::vector &dimensions) const = 0; + /* * Creates a new tensor by modifying the underlying cells matching * the given cells applying a join function to determine the new * cell value. */ virtual std::unique_ptr modify(join_fun_t op, const CellValues &cellValues) const = 0; + + /** + * Creates a new tensor by adding the cells of the argument tensor to this tensor. + * Existing cell values are overwritten. + */ + virtual std::unique_ptr add(const Tensor &arg) const = 0; + virtual bool equals(const Tensor &arg) const = 0; // want to remove, but needed by document virtual Tensor::UP clone() const = 0; // want to remove, but needed by document virtual eval::TensorSpec toSpec() const = 0; diff --git a/eval/src/vespa/eval/tensor/tensor_address_element_iterator.h b/eval/src/vespa/eval/tensor/tensor_address_element_iterator.h index 0e8d88b3a1e..e413712362f 100644 --- a/eval/src/vespa/eval/tensor/tensor_address_element_iterator.h +++ b/eval/src/vespa/eval/tensor/tensor_address_element_iterator.h @@ -2,8 +2,9 @@ #pragma once -namespace vespalib { -namespace tensor { +#include + +namespace vespalib::tensor { using DimensionsSet = vespalib::hash_set; @@ -40,5 +41,4 @@ public: } }; -} // namespace vespalib::tensor -} // namespace vespalib +} diff --git a/eval/src/vespa/eval/tensor/wrapped_simple_tensor.cpp b/eval/src/vespa/eval/tensor/wrapped_simple_tensor.cpp index 394335d9b67..66fd2978a53 100644 --- a/eval/src/vespa/eval/tensor/wrapped_simple_tensor.cpp +++ b/eval/src/vespa/eval/tensor/wrapped_simple_tensor.cpp @@ -83,4 +83,10 @@ WrappedSimpleTensor::modify(join_fun_t, const CellValues &) const LOG_ABORT("should not be reached"); } +std::unique_ptr +WrappedSimpleTensor::add(const Tensor &) const +{ + LOG_ABORT("should not be reached"); +} + } // namespace vespalib::tensor diff --git a/eval/src/vespa/eval/tensor/wrapped_simple_tensor.h b/eval/src/vespa/eval/tensor/wrapped_simple_tensor.h index 511fbc3c795..2d877b6fbbc 100644 --- a/eval/src/vespa/eval/tensor/wrapped_simple_tensor.h +++ b/eval/src/vespa/eval/tensor/wrapped_simple_tensor.h @@ -39,6 +39,7 @@ public: Tensor::UP join(join_fun_t, const Tensor &) const override; Tensor::UP reduce(join_fun_t, const std::vector &) const override; std::unique_ptr modify(join_fun_t, const CellValues &) const override; + std::unique_ptr add(const Tensor &arg) const override; }; } // namespace vespalib::tensor -- cgit v1.2.3 From 33b21d16da3230ed1bbf6b1aa39e56594b1bf095 Mon Sep 17 00:00:00 2001 From: Geir Storli Date: Fri, 8 Feb 2019 12:18:02 +0000 Subject: Rename unit test tensor_modify -> tensor_modify_operation. --- eval/CMakeLists.txt | 2 +- eval/src/tests/tensor/tensor_modify/CMakeLists.txt | 8 -- .../tensor/tensor_modify/tensor_modify_test.cpp | 92 ---------------------- .../tensor/tensor_modify_operation/CMakeLists.txt | 8 ++ .../tensor_modify_operation_test.cpp | 92 ++++++++++++++++++++++ 5 files changed, 101 insertions(+), 101 deletions(-) delete mode 100644 eval/src/tests/tensor/tensor_modify/CMakeLists.txt delete mode 100644 eval/src/tests/tensor/tensor_modify/tensor_modify_test.cpp create mode 100644 eval/src/tests/tensor/tensor_modify_operation/CMakeLists.txt create mode 100644 eval/src/tests/tensor/tensor_modify_operation/tensor_modify_operation_test.cpp (limited to 'eval/src') diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt index 040a98290d2..9f59f6a71a6 100644 --- a/eval/CMakeLists.txt +++ b/eval/CMakeLists.txt @@ -40,7 +40,7 @@ vespa_define_module( src/tests/tensor/tensor_address src/tests/tensor/tensor_conformance src/tests/tensor/tensor_mapper - src/tests/tensor/tensor_modify + src/tests/tensor/tensor_modify_operation src/tests/tensor/tensor_performance src/tests/tensor/tensor_serialization src/tests/tensor/tensor_slime_serialization diff --git a/eval/src/tests/tensor/tensor_modify/CMakeLists.txt b/eval/src/tests/tensor/tensor_modify/CMakeLists.txt deleted file mode 100644 index 2d4055db7e2..00000000000 --- a/eval/src/tests/tensor/tensor_modify/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(eval_tensor_modify_test_app TEST - SOURCES - tensor_modify_test.cpp - DEPENDS - vespaeval -) -vespa_add_test(NAME eval_tensor_modify_test_app COMMAND eval_tensor_modify_test_app) diff --git a/eval/src/tests/tensor/tensor_modify/tensor_modify_test.cpp b/eval/src/tests/tensor/tensor_modify/tensor_modify_test.cpp deleted file mode 100644 index c3c817d28c4..00000000000 --- a/eval/src/tests/tensor/tensor_modify/tensor_modify_test.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include -#include -#include -#include -#include -#include - -using vespalib::eval::Value; -using vespalib::eval::TensorSpec; -using namespace vespalib::tensor; - -namespace { - -double -replace(double, double b) -{ - return b; -} - -template -const Tensor *asTensor(Value &value) -{ - auto *tensor = dynamic_cast(value.as_tensor()); - ASSERT_TRUE(tensor); - return tensor; -} - -} - -void checkUpdate(const TensorSpec &source, const TensorSpec &update, const TensorSpec &expect) { - auto sourceValue = DefaultTensorEngine::ref().from_spec(source); - auto sourceTensor = asTensor(*sourceValue); - auto updateValue = DefaultTensorEngine::ref().from_spec(update); - auto updateTensor = asTensor(*updateValue); - const CellValues cellValues(*updateTensor); - auto actualTensor = sourceTensor->modify(replace, cellValues); - auto actual = actualTensor->toSpec(); - auto expectValue = DefaultTensorEngine::ref().from_spec(expect); - auto expectTensor = asTensor(*expectValue); - auto expectPadded = expectTensor->toSpec(); - EXPECT_EQUAL(actual, expectPadded); -} - -TEST("require that sparse tensors can be modified") { - checkUpdate(TensorSpec("tensor(x{},y{})") - .add({{"x","8"},{"y","9"}}, 11) - .add({{"x","9"},{"y","9"}}, 11), - TensorSpec("tensor(x{},y{})") - .add({{"x","8"},{"y","9"}}, 2), - TensorSpec("tensor(x{},y{})") - .add({{"x","8"},{"y","9"}}, 2) - .add({{"x","9"},{"y","9"}}, 11)); -} - -TEST("require that dense tensors can be modified") { - checkUpdate(TensorSpec("tensor(x[10],y[10])") - .add({{"x",8},{"y",9}}, 11) - .add({{"x",9},{"y",9}}, 11), - TensorSpec("tensor(x{},y{})") - .add({{"x","8"},{"y","9"}}, 2), - TensorSpec("tensor(x[10],y[10])") - .add({{"x",8},{"y",9}}, 2) - .add({{"x",9},{"y",9}}, 11)); -} - -TEST("require that sparse tensors ignore updates to missing cells") { - checkUpdate(TensorSpec("tensor(x{},y{})") - .add({{"x","8"},{"y","9"}}, 11) - .add({{"x","9"},{"y","9"}}, 11), - TensorSpec("tensor(x{},y{})") - .add({{"x","7"},{"y","9"}}, 2) - .add({{"x","8"},{"y","9"}}, 2), - TensorSpec("tensor(x{},y{})") - .add({{"x","8"},{"y","9"}}, 2) - .add({{"x","9"},{"y","9"}}, 11)); -} - -TEST("require that dense tensors ignore updates to out of range cells") { - checkUpdate(TensorSpec("tensor(x[10],y[10])") - .add({{"x",8},{"y",9}}, 11) - .add({{"x",9},{"y",9}}, 11), - TensorSpec("tensor(x{},y{})") - .add({{"x","8"},{"y","9"}}, 2) - .add({{"x","10"},{"y","9"}}, 2), - TensorSpec("tensor(x[10],y[10])") - .add({{"x",8},{"y",9}}, 2) - .add({{"x",9},{"y",9}}, 11)); -} - -TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/eval/src/tests/tensor/tensor_modify_operation/CMakeLists.txt b/eval/src/tests/tensor/tensor_modify_operation/CMakeLists.txt new file mode 100644 index 00000000000..b0ffa48eb3b --- /dev/null +++ b/eval/src/tests/tensor/tensor_modify_operation/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(eval_tensor_modify_operation_test_app TEST + SOURCES + tensor_modify_operation_test.cpp + DEPENDS + vespaeval +) +vespa_add_test(NAME eval_tensor_modify_operation_test_app COMMAND eval_tensor_modify_operation_test_app) diff --git a/eval/src/tests/tensor/tensor_modify_operation/tensor_modify_operation_test.cpp b/eval/src/tests/tensor/tensor_modify_operation/tensor_modify_operation_test.cpp new file mode 100644 index 00000000000..c3c817d28c4 --- /dev/null +++ b/eval/src/tests/tensor/tensor_modify_operation/tensor_modify_operation_test.cpp @@ -0,0 +1,92 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include +#include +#include +#include +#include +#include + +using vespalib::eval::Value; +using vespalib::eval::TensorSpec; +using namespace vespalib::tensor; + +namespace { + +double +replace(double, double b) +{ + return b; +} + +template +const Tensor *asTensor(Value &value) +{ + auto *tensor = dynamic_cast(value.as_tensor()); + ASSERT_TRUE(tensor); + return tensor; +} + +} + +void checkUpdate(const TensorSpec &source, const TensorSpec &update, const TensorSpec &expect) { + auto sourceValue = DefaultTensorEngine::ref().from_spec(source); + auto sourceTensor = asTensor(*sourceValue); + auto updateValue = DefaultTensorEngine::ref().from_spec(update); + auto updateTensor = asTensor(*updateValue); + const CellValues cellValues(*updateTensor); + auto actualTensor = sourceTensor->modify(replace, cellValues); + auto actual = actualTensor->toSpec(); + auto expectValue = DefaultTensorEngine::ref().from_spec(expect); + auto expectTensor = asTensor(*expectValue); + auto expectPadded = expectTensor->toSpec(); + EXPECT_EQUAL(actual, expectPadded); +} + +TEST("require that sparse tensors can be modified") { + checkUpdate(TensorSpec("tensor(x{},y{})") + .add({{"x","8"},{"y","9"}}, 11) + .add({{"x","9"},{"y","9"}}, 11), + TensorSpec("tensor(x{},y{})") + .add({{"x","8"},{"y","9"}}, 2), + TensorSpec("tensor(x{},y{})") + .add({{"x","8"},{"y","9"}}, 2) + .add({{"x","9"},{"y","9"}}, 11)); +} + +TEST("require that dense tensors can be modified") { + checkUpdate(TensorSpec("tensor(x[10],y[10])") + .add({{"x",8},{"y",9}}, 11) + .add({{"x",9},{"y",9}}, 11), + TensorSpec("tensor(x{},y{})") + .add({{"x","8"},{"y","9"}}, 2), + TensorSpec("tensor(x[10],y[10])") + .add({{"x",8},{"y",9}}, 2) + .add({{"x",9},{"y",9}}, 11)); +} + +TEST("require that sparse tensors ignore updates to missing cells") { + checkUpdate(TensorSpec("tensor(x{},y{})") + .add({{"x","8"},{"y","9"}}, 11) + .add({{"x","9"},{"y","9"}}, 11), + TensorSpec("tensor(x{},y{})") + .add({{"x","7"},{"y","9"}}, 2) + .add({{"x","8"},{"y","9"}}, 2), + TensorSpec("tensor(x{},y{})") + .add({{"x","8"},{"y","9"}}, 2) + .add({{"x","9"},{"y","9"}}, 11)); +} + +TEST("require that dense tensors ignore updates to out of range cells") { + checkUpdate(TensorSpec("tensor(x[10],y[10])") + .add({{"x",8},{"y",9}}, 11) + .add({{"x",9},{"y",9}}, 11), + TensorSpec("tensor(x{},y{})") + .add({{"x","8"},{"y","9"}}, 2) + .add({{"x","10"},{"y","9"}}, 2), + TensorSpec("tensor(x[10],y[10])") + .add({{"x",8},{"y",9}}, 2) + .add({{"x",9},{"y",9}}, 11)); +} + +TEST_MAIN() { TEST_RUN_ALL(); } -- cgit v1.2.3 From 808a7684e549f6b3d2d30f7b8b217ba76a80e8df Mon Sep 17 00:00:00 2001 From: Geir Storli Date: Fri, 8 Feb 2019 12:50:02 +0000 Subject: Update Tensor forward declarations. --- document/src/vespa/document/fieldvalue/tensorfieldvalue.h | 2 +- document/src/vespa/document/update/tensoraddupdate.h | 2 +- document/src/vespa/document/update/tensormodifyupdate.h | 2 +- eval/src/vespa/eval/tensor/dense/dense_tensor_apply.h | 2 +- eval/src/vespa/eval/tensor/serialization/slime_binary_format.h | 2 +- eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h | 2 +- eval/src/vespa/eval/tensor/serialization/typed_binary_format.h | 2 +- eval/src/vespa/eval/tensor/sparse/sparse_tensor_apply.h | 2 +- eval/src/vespa/eval/tensor/tensor_builder.h | 2 +- eval/src/vespa/eval/tensor/tensor_factory.h | 2 +- eval/src/vespa/eval/tensor/tensor_mapper.h | 2 +- searchlib/src/vespa/searchlib/index/docbuilder.h | 2 +- searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h | 2 +- searchlib/src/vespa/searchlib/tensor/tensor_store.h | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'eval/src') diff --git a/document/src/vespa/document/fieldvalue/tensorfieldvalue.h b/document/src/vespa/document/fieldvalue/tensorfieldvalue.h index 49088c587c6..5c831601d1a 100644 --- a/document/src/vespa/document/fieldvalue/tensorfieldvalue.h +++ b/document/src/vespa/document/fieldvalue/tensorfieldvalue.h @@ -4,7 +4,7 @@ #include "fieldvalue.h" -namespace vespalib { namespace tensor { struct Tensor; } } +namespace vespalib { namespace tensor { class Tensor; } } namespace document { diff --git a/document/src/vespa/document/update/tensoraddupdate.h b/document/src/vespa/document/update/tensoraddupdate.h index 52e44ea33f3..a92ff0101f0 100644 --- a/document/src/vespa/document/update/tensoraddupdate.h +++ b/document/src/vespa/document/update/tensoraddupdate.h @@ -2,7 +2,7 @@ #include "valueupdate.h" -namespace vespalib::tensor { struct Tensor; } +namespace vespalib::tensor { class Tensor; } namespace document { diff --git a/document/src/vespa/document/update/tensormodifyupdate.h b/document/src/vespa/document/update/tensormodifyupdate.h index 65cf9f2c0e3..dcb9bcf0470 100644 --- a/document/src/vespa/document/update/tensormodifyupdate.h +++ b/document/src/vespa/document/update/tensormodifyupdate.h @@ -2,7 +2,7 @@ #include "valueupdate.h" -namespace vespalib::tensor { struct Tensor; } +namespace vespalib::tensor { class Tensor; } namespace document { 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 52d49b8e95b..49e075f6999 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.h +++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_apply.h @@ -3,7 +3,7 @@ #pragma once namespace vespalib::tensor { - struct Tensor; + class Tensor; class DenseTensor; } diff --git a/eval/src/vespa/eval/tensor/serialization/slime_binary_format.h b/eval/src/vespa/eval/tensor/serialization/slime_binary_format.h index b53a3af9e19..f1366c64e2c 100644 --- a/eval/src/vespa/eval/tensor/serialization/slime_binary_format.h +++ b/eval/src/vespa/eval/tensor/serialization/slime_binary_format.h @@ -12,7 +12,7 @@ namespace slime { struct Inserter; } namespace tensor { -struct Tensor; +class Tensor; class TensorBuilder; /** diff --git a/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h b/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h index 23d77a5c704..db05574dfce 100644 --- a/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h +++ b/eval/src/vespa/eval/tensor/serialization/sparse_binary_format.h @@ -8,7 +8,7 @@ class nbostream; namespace tensor { -struct Tensor; +class Tensor; class TensorBuilder; /** diff --git a/eval/src/vespa/eval/tensor/serialization/typed_binary_format.h b/eval/src/vespa/eval/tensor/serialization/typed_binary_format.h index 38c3373213c..c655210907f 100644 --- a/eval/src/vespa/eval/tensor/serialization/typed_binary_format.h +++ b/eval/src/vespa/eval/tensor/serialization/typed_binary_format.h @@ -11,7 +11,7 @@ class nbostream; namespace tensor { -struct Tensor; +class Tensor; class TensorBuilder; /** diff --git a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_apply.h b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_apply.h index 2c1c57de8ac..ec6edf2d847 100644 --- a/eval/src/vespa/eval/tensor/sparse/sparse_tensor_apply.h +++ b/eval/src/vespa/eval/tensor/sparse/sparse_tensor_apply.h @@ -3,7 +3,7 @@ #pragma once namespace vespalib::tensor { - struct Tensor; + class Tensor; class SparseTensor; } diff --git a/eval/src/vespa/eval/tensor/tensor_builder.h b/eval/src/vespa/eval/tensor/tensor_builder.h index 205da137895..05238b27df5 100644 --- a/eval/src/vespa/eval/tensor/tensor_builder.h +++ b/eval/src/vespa/eval/tensor/tensor_builder.h @@ -7,7 +7,7 @@ namespace vespalib { namespace tensor { -struct Tensor; +class Tensor; /** * An interfrace for builder of tensors (sparse multi-dimensional array). diff --git a/eval/src/vespa/eval/tensor/tensor_factory.h b/eval/src/vespa/eval/tensor/tensor_factory.h index f3c9aae7328..5fe31afc4dd 100644 --- a/eval/src/vespa/eval/tensor/tensor_factory.h +++ b/eval/src/vespa/eval/tensor/tensor_factory.h @@ -8,7 +8,7 @@ namespace vespalib { namespace tensor { -struct Tensor; +class Tensor; class TensorBuilder; /** diff --git a/eval/src/vespa/eval/tensor/tensor_mapper.h b/eval/src/vespa/eval/tensor/tensor_mapper.h index 6218146496a..99994bd15e8 100644 --- a/eval/src/vespa/eval/tensor/tensor_mapper.h +++ b/eval/src/vespa/eval/tensor/tensor_mapper.h @@ -7,7 +7,7 @@ namespace vespalib { namespace tensor { -struct Tensor; +class Tensor; /** * Class to map a tensor to a given tensor type. Dimensions in input diff --git a/searchlib/src/vespa/searchlib/index/docbuilder.h b/searchlib/src/vespa/searchlib/index/docbuilder.h index a9752cdb164..73c60304f50 100644 --- a/searchlib/src/vespa/searchlib/index/docbuilder.h +++ b/searchlib/src/vespa/searchlib/index/docbuilder.h @@ -13,7 +13,7 @@ #include #include -namespace vespalib { namespace tensor { struct Tensor; } } +namespace vespalib { namespace tensor { class Tensor; } } namespace search { namespace index { diff --git a/searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h b/searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h index e7b2c64e464..6c83d3caae9 100644 --- a/searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h +++ b/searchlib/src/vespa/searchlib/tensor/i_tensor_attribute.h @@ -6,7 +6,7 @@ namespace vespalib::tensor { class MutableDenseTensorView; -struct Tensor; +class Tensor; } namespace vespalib::eval { class ValueType; } diff --git a/searchlib/src/vespa/searchlib/tensor/tensor_store.h b/searchlib/src/vespa/searchlib/tensor/tensor_store.h index 6da1e341704..43667158d89 100644 --- a/searchlib/src/vespa/searchlib/tensor/tensor_store.h +++ b/searchlib/src/vespa/searchlib/tensor/tensor_store.h @@ -6,7 +6,7 @@ #include #include -namespace vespalib { namespace tensor { struct Tensor; } } +namespace vespalib { namespace tensor { class Tensor; } } namespace search { -- cgit v1.2.3