diff options
author | Håvard Pettersen <havardpe@oath.com> | 2017-11-09 14:18:11 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2017-11-09 14:18:11 +0000 |
commit | 56c26cfe5d3fd41169d928180f91d029b1295adf (patch) | |
tree | 95a77a19c31764e3984877eb516eae8444fc5713 /eval | |
parent | 9d47aad83ad4750fbfeb934c4a85abf353988974 (diff) |
use const references and stash instead of UP
Diffstat (limited to 'eval')
15 files changed, 201 insertions, 222 deletions
diff --git a/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp b/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp index 0f62e69b081..76f776df552 100644 --- a/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp +++ b/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp @@ -2,6 +2,7 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/function.h> #include <vespa/eval/eval/tensor_spec.h> +#include <vespa/eval/eval/operation.h> #include <vespa/eval/eval/interpreted_function.h> #include <vespa/eval/eval/test/eval_spec.h> #include <vespa/eval/eval/basic_nodes.h> diff --git a/eval/src/tests/eval/tensor_function/tensor_function_test.cpp b/eval/src/tests/eval/tensor_function/tensor_function_test.cpp index 150ec8a25db..681a4dabc19 100644 --- a/eval/src/tests/eval/tensor_function/tensor_function_test.cpp +++ b/eval/src/tests/eval/tensor_function/tensor_function_test.cpp @@ -12,26 +12,26 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::tensor_function; -struct EvalCtx : TensorFunction::Input { +struct EvalCtx { const TensorEngine &engine; Stash stash; ErrorValue error; - std::map<size_t, Value::UP> tensors; + std::vector<Value::UP> tensors; + std::vector<Value::CREF> params; EvalCtx(const TensorEngine &engine_in) : engine(engine_in), stash(), error(), tensors() {} ~EvalCtx() {} - void add_tensor(Value::UP tensor, size_t id) { - tensors.emplace(id, std::move(tensor)); + size_t add_tensor(Value::UP tensor) { + size_t id = params.size(); + params.emplace_back(*tensor); + tensors.push_back(std::move(tensor)); + return id; } - const Value &get_tensor(size_t id) const override { - if (tensors.count(id) == 0) { - return error; - } - return *tensors.find(id)->second; + const Value &eval(const TensorFunction &fun) { + return fun.eval(params, stash); } - const Value &eval(const TensorFunction &fun) { return fun.eval(*this, stash); } - TensorFunction::UP compile(tensor_function::Node_UP expr) const { - return engine.compile(std::move(expr)); + const TensorFunction &compile(const tensor_function::Node &expr) { + return engine.compile(expr, stash); } Value::UP make_tensor_inject() { return engine.from_spec( @@ -110,54 +110,56 @@ void verify_equal(const Value &expect, const Value &value) { TEST("require that tensor injection works") { EvalCtx ctx(SimpleTensorEngine::ref()); - ctx.add_tensor(ctx.make_tensor_inject(), 1); + size_t a_id = ctx.add_tensor(ctx.make_tensor_inject()); Value::UP expect = ctx.make_tensor_inject(); - auto fun = inject(ValueType::from_spec("tensor(x[2],y[2])"), 1); - EXPECT_EQUAL(expect->type(), fun->result_type); - auto prog = ctx.compile(std::move(fun)); - TEST_DO(verify_equal(*expect, ctx.eval(*prog))); + const auto &fun = inject(ValueType::from_spec("tensor(x[2],y[2])"), a_id, ctx.stash); + EXPECT_EQUAL(expect->type(), fun.result_type); + const auto &prog = ctx.compile(fun); + TEST_DO(verify_equal(*expect, ctx.eval(prog))); } TEST("require that partial tensor reduction works") { EvalCtx ctx(SimpleTensorEngine::ref()); - ctx.add_tensor(ctx.make_tensor_reduce_input(), 1); + size_t a_id = ctx.add_tensor(ctx.make_tensor_reduce_input()); Value::UP expect = ctx.make_tensor_reduce_y_output(); - auto fun = reduce(inject(ValueType::from_spec("tensor(x[3],y[2])"), 1), Aggr::SUM, {"y"}); - EXPECT_EQUAL(expect->type(), fun->result_type); - auto prog = ctx.compile(std::move(fun)); - TEST_DO(verify_equal(*expect, ctx.eval(*prog))); + const auto &fun = reduce(inject(ValueType::from_spec("tensor(x[3],y[2])"), a_id, ctx.stash), Aggr::SUM, {"y"}, ctx.stash); + EXPECT_EQUAL(expect->type(), fun.result_type); + const auto &prog = ctx.compile(fun); + TEST_DO(verify_equal(*expect, ctx.eval(prog))); } TEST("require that full tensor reduction works") { EvalCtx ctx(SimpleTensorEngine::ref()); - ctx.add_tensor(ctx.make_tensor_reduce_input(), 1); - auto fun = reduce(inject(ValueType::from_spec("tensor(x[3],y[2])"), 1), Aggr::SUM, {}); - EXPECT_EQUAL(ValueType::from_spec("double"), fun->result_type); - auto prog = ctx.compile(std::move(fun)); - EXPECT_EQUAL(21.0, ctx.eval(*prog).as_double()); + size_t a_id = ctx.add_tensor(ctx.make_tensor_reduce_input()); + const auto &fun = reduce(inject(ValueType::from_spec("tensor(x[3],y[2])"), a_id, ctx.stash), Aggr::SUM, {}, ctx.stash); + EXPECT_EQUAL(ValueType::from_spec("double"), fun.result_type); + const auto &prog = ctx.compile(fun); + const Value &result = ctx.eval(prog); + EXPECT_TRUE(result.is_double()); + EXPECT_EQUAL(21.0, result.as_double()); } TEST("require that tensor map works") { EvalCtx ctx(SimpleTensorEngine::ref()); - ctx.add_tensor(ctx.make_tensor_map_input(), 1); + size_t a_id = ctx.add_tensor(ctx.make_tensor_map_input()); Value::UP expect = ctx.make_tensor_map_output(); - auto fun = map(inject(ValueType::from_spec("tensor(x{},y{})"), 1), operation::Neg::f); - EXPECT_EQUAL(expect->type(), fun->result_type); - auto prog = ctx.compile(std::move(fun)); - TEST_DO(verify_equal(*expect, ctx.eval(*prog))); + const auto &fun = map(inject(ValueType::from_spec("tensor(x{},y{})"), a_id, ctx.stash), operation::Neg::f, ctx.stash); + EXPECT_EQUAL(expect->type(), fun.result_type); + const auto &prog = ctx.compile(fun); + TEST_DO(verify_equal(*expect, ctx.eval(prog))); } TEST("require that tensor join works") { EvalCtx ctx(SimpleTensorEngine::ref()); - ctx.add_tensor(ctx.make_tensor_apply_lhs(), 1); - ctx.add_tensor(ctx.make_tensor_apply_rhs(), 2); + size_t a_id = ctx.add_tensor(ctx.make_tensor_apply_lhs()); + size_t b_id = ctx.add_tensor(ctx.make_tensor_apply_rhs()); Value::UP expect = ctx.make_tensor_apply_output(); - auto fun = join(inject(ValueType::from_spec("tensor(x{},y{})"), 1), - inject(ValueType::from_spec("tensor(y{},z{})"), 2), - operation::Mul::f); - EXPECT_EQUAL(expect->type(), fun->result_type); - auto prog = ctx.compile(std::move(fun)); - TEST_DO(verify_equal(*expect, ctx.eval(*prog))); + const auto &fun = join(inject(ValueType::from_spec("tensor(x{},y{})"), a_id, ctx.stash), + inject(ValueType::from_spec("tensor(y{},z{})"), b_id, ctx.stash), + operation::Mul::f, ctx.stash); + EXPECT_EQUAL(expect->type(), fun.result_type); + const auto &prog = ctx.compile(fun); + TEST_DO(verify_equal(*expect, ctx.eval(prog))); } TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/eval/src/tests/tensor/dense_dot_product_function/dense_dot_product_function_test.cpp b/eval/src/tests/tensor/dense_dot_product_function/dense_dot_product_function_test.cpp index f272166fede..ca77997bac7 100644 --- a/eval/src/tests/tensor/dense_dot_product_function/dense_dot_product_function_test.cpp +++ b/eval/src/tests/tensor/dense_dot_product_function/dense_dot_product_function_test.cpp @@ -50,13 +50,14 @@ asDenseTensor(const tensor::Tensor &tensor) return dynamic_cast<const DenseTensor &>(tensor); } -class FunctionInput : public TensorFunction::Input +class FunctionInput { private: tensor::Tensor::UP _lhsTensor; tensor::Tensor::UP _rhsTensor; const DenseTensor &_lhsDenseTensor; const DenseTensor &_rhsDenseTensor; + std::vector<Value::CREF> _params; public: FunctionInput(size_t lhsNumCells, size_t rhsNumCells) @@ -64,14 +65,11 @@ public: _rhsTensor(makeTensor(rhsNumCells, 5.0)), _lhsDenseTensor(asDenseTensor(*_lhsTensor)), _rhsDenseTensor(asDenseTensor(*_rhsTensor)) - {} - virtual const Value &get_tensor(size_t id) const override { - if (id == 0) { - return *_lhsTensor; - } else { - return *_rhsTensor; - } + { + _params.emplace_back(_lhsDenseTensor); + _params.emplace_back(_rhsDenseTensor); } + ConstArrayRef<Value::CREF> get() const { return _params; } double expectedDotProduct() const { return calcDotProduct(_lhsDenseTensor, _rhsDenseTensor); } @@ -85,11 +83,11 @@ struct Fixture ~Fixture(); double eval() const { Stash stash; - const Value &result = function.eval(input, stash); + const Value &result = function.eval(input.get(), stash); ASSERT_TRUE(result.is_double()); LOG(info, "eval(): (%s) * (%s) = %f", - input.get_tensor(0).type().to_spec().c_str(), - input.get_tensor(1).type().to_spec().c_str(), + input.get()[0].get().type().to_spec().c_str(), + input.get()[1].get().type().to_spec().c_str(), result.as_double()); return result.as_double(); } diff --git a/eval/src/tests/tensor/dense_tensor_function_compiler/dense_tensor_function_compiler_test.cpp b/eval/src/tests/tensor/dense_tensor_function_compiler/dense_tensor_function_compiler_test.cpp index 6dcfc0791e7..63829650cc5 100644 --- a/eval/src/tests/tensor/dense_tensor_function_compiler/dense_tensor_function_compiler_test.cpp +++ b/eval/src/tests/tensor/dense_tensor_function_compiler/dense_tensor_function_compiler_test.cpp @@ -3,32 +3,36 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/tensor/dense/dense_dot_product_function.h> #include <vespa/eval/tensor/dense/dense_tensor_function_compiler.h> +#include <vespa/eval/eval/operation.h> using namespace vespalib::eval; using namespace vespalib::eval::operation; using namespace vespalib::eval::tensor_function; using namespace vespalib::tensor; +using vespalib::Stash; template <typename T> const T *as(const TensorFunction &function) { return dynamic_cast<const T *>(&function); } -TensorFunction::UP +const TensorFunction & compileDotProduct(const vespalib::string &lhsType, - const vespalib::string &rhsType) + const vespalib::string &rhsType, + Stash &stash) { - Node_UP reduceNode = reduce(join(inject(ValueType::from_spec(lhsType), 1), - inject(ValueType::from_spec(rhsType), 3), - Mul::f), - Aggr::SUM, {}); - return DenseTensorFunctionCompiler::compile(std::move(reduceNode)); + const Node &reduceNode = reduce(join(inject(ValueType::from_spec(lhsType), 1, stash), + inject(ValueType::from_spec(rhsType), 3, stash), + Mul::f, stash), + Aggr::SUM, {}, stash); + return DenseTensorFunctionCompiler::compile(reduceNode, stash); } void assertCompiledDotProduct(const vespalib::string &lhsType, const vespalib::string &rhsType) { - TensorFunction::UP func = compileDotProduct(lhsType, rhsType); - const DenseDotProductFunction *dotProduct = as<DenseDotProductFunction>(*func); + Stash stash; + const TensorFunction &func = compileDotProduct(lhsType, rhsType, stash); + const DenseDotProductFunction *dotProduct = as<DenseDotProductFunction>(func); ASSERT_TRUE(dotProduct); EXPECT_EQUAL(1u, dotProduct->lhsTensorId()); EXPECT_EQUAL(3u, dotProduct->rhsTensorId()); @@ -38,8 +42,9 @@ void assertNotCompiledDotProduct(const vespalib::string &lhsType, const vespalib::string &rhsType) { - TensorFunction::UP func = compileDotProduct(lhsType, rhsType); - const Reduce *reduce = as<Reduce>(*func); + Stash stash; + const TensorFunction &func = compileDotProduct(lhsType, rhsType, stash); + const Reduce *reduce = as<Reduce>(func); EXPECT_TRUE(reduce); } diff --git a/eval/src/vespa/eval/eval/interpreted_function.cpp b/eval/src/vespa/eval/eval/interpreted_function.cpp index 7e80a699107..59d6753e142 100644 --- a/eval/src/vespa/eval/eval/interpreted_function.cpp +++ b/eval/src/vespa/eval/eval/interpreted_function.cpp @@ -5,6 +5,7 @@ #include "node_traverser.h" #include "check_type.h" #include "tensor_spec.h" +#include "operation.h" #include <vespa/vespalib/util/classname.h> #include <vespa/eval/eval/llvm/compile_cache.h> #include <vespa/vespalib/util/benchmark_timer.h> @@ -118,32 +119,19 @@ const T &undef_cref() { } struct TensorFunctionArgArgMeta { - TensorFunction::UP function; + const TensorFunction &function; size_t param1; size_t param2; - TensorFunctionArgArgMeta(TensorFunction::UP function_in, size_t param1_in, size_t param2_in) - : function(std::move(function_in)), param1(param1_in), param2(param2_in) {} -}; - -struct ArgArgInput : TensorFunction::Input { - const TensorFunctionArgArgMeta &meta; - State &state; - ArgArgInput(const TensorFunctionArgArgMeta &meta_in, State &state_in) - : meta(meta_in), state(state_in) {} - const Value &get_tensor(size_t id) const override { - if (id == 0) { - return state.params->resolve(meta.param1, state.stash); - } else if (id == 1) { - return state.params->resolve(meta.param2, state.stash); - } - return undef_cref<Value>(); - } + TensorFunctionArgArgMeta(const TensorFunction &function_in, size_t param1_in, size_t param2_in) + : function(function_in), param1(param1_in), param2(param2_in) {} }; void op_tensor_function_arg_arg(State &state, uint64_t param) { const TensorFunctionArgArgMeta &meta = unwrap_param<TensorFunctionArgArgMeta>(param); - ArgArgInput input(meta, state); - state.stack.push_back(meta.function->eval(input, state.stash)); + Value::CREF params[2] = + {state.params->resolve(meta.param1, state.stash), + state.params->resolve(meta.param2, state.stash)}; + state.stack.push_back(meta.function.eval(ConstArrayRef<Value::CREF>(params, 2), state.stash)); } //----------------------------------------------------------------------------- @@ -279,12 +267,12 @@ struct ProgramBuilder : public NodeVisitor, public NodeTraverser { program.pop_back(); // load auto a = as<Symbol>(node.get_child(0).get_child(0)); auto b = as<Symbol>(node.get_child(0).get_child(1)); - auto ir = tensor_function::reduce(tensor_function::join( - tensor_function::inject(types.get_type(*a), 0), - tensor_function::inject(types.get_type(*b), 1), - operation::Mul::f), node.aggr(), node.dimensions()); - auto fun = tensor_engine.compile(std::move(ir)); - const auto &meta = stash.create<TensorFunctionArgArgMeta>(std::move(fun), a->id(), b->id()); + const auto &ir = tensor_function::reduce(tensor_function::join( + tensor_function::inject(types.get_type(*a), 0, stash), + tensor_function::inject(types.get_type(*b), 1, stash), + operation::Mul::f, stash), node.aggr(), node.dimensions(), stash); + const auto &fun = tensor_engine.compile(ir, stash); + const auto &meta = stash.create<TensorFunctionArgArgMeta>(fun, a->id(), b->id()); program.emplace_back(op_tensor_function_arg_arg, wrap_param<TensorFunctionArgArgMeta>(meta)); } else { ReduceParams ¶ms = stash.create<ReduceParams>(node.aggr(), node.dimensions()); diff --git a/eval/src/vespa/eval/eval/tensor_engine.h b/eval/src/vespa/eval/eval/tensor_engine.h index 357b9c8f82f..02a7f0c655a 100644 --- a/eval/src/vespa/eval/eval/tensor_engine.h +++ b/eval/src/vespa/eval/eval/tensor_engine.h @@ -34,21 +34,21 @@ struct TensorEngine { using Aggr = eval::Aggr; using Tensor = eval::Tensor; + using TensorFunction = eval::TensorFunction; using TensorSpec = eval::TensorSpec; using Value = eval::Value; using ValueType = eval::ValueType; using join_fun_t = double (*)(double, double); using map_fun_t = double (*)(double); - virtual TensorFunction::UP compile(tensor_function::Node_UP expr) const { return std::move(expr); } - - // havardpe: new API, WIP virtual TensorSpec to_spec(const Value &value) const = 0; virtual Value::UP from_spec(const TensorSpec &spec) const = 0; virtual void encode(const Value &value, nbostream &output) const = 0; virtual Value::UP decode(nbostream &input) const = 0; + virtual const TensorFunction &compile(const tensor_function::Node &expr, Stash &) const { return expr; } + virtual const Value &map(const Value &a, map_fun_t function, Stash &stash) const = 0; virtual const Value &join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const = 0; virtual const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const = 0; diff --git a/eval/src/vespa/eval/eval/tensor_function.cpp b/eval/src/vespa/eval/eval/tensor_function.cpp index ef91d9e10a9..9cd7c7fc9c2 100644 --- a/eval/src/vespa/eval/eval/tensor_function.cpp +++ b/eval/src/vespa/eval/eval/tensor_function.cpp @@ -20,63 +20,58 @@ const TensorEngine &infer_engine(const std::initializer_list<Value::CREF> &value return SimpleTensorEngine::ref(); } -void Inject::accept(TensorFunctionVisitor &visitor) const { visitor.visit(*this); } -void Reduce::accept(TensorFunctionVisitor &visitor) const { visitor.visit(*this); } -void Map ::accept(TensorFunctionVisitor &visitor) const { visitor.visit(*this); } -void Join ::accept(TensorFunctionVisitor &visitor) const { visitor.visit(*this); } - //----------------------------------------------------------------------------- const Value & -Inject::eval(const Input &input, Stash &) const +Inject::eval(ConstArrayRef<Value::CREF> params, Stash &) const { - return input.get_tensor(tensor_id); + return params[tensor_id]; } const Value & -Reduce::eval(const Input &input, Stash &stash) const +Reduce::eval(ConstArrayRef<Value::CREF> params, Stash &stash) const { - const Value &a = tensor->eval(input, stash); + const Value &a = tensor.eval(params, stash); const TensorEngine &engine = infer_engine({a}); return engine.reduce(a, aggr, dimensions, stash); } const Value & -Map::eval(const Input &input, Stash &stash) const +Map::eval(ConstArrayRef<Value::CREF> params, Stash &stash) const { - const Value &a = tensor->eval(input, stash); + const Value &a = tensor.eval(params, stash); const TensorEngine &engine = infer_engine({a}); return engine.map(a, function, stash); } const Value & -Join::eval(const Input &input, Stash &stash) const +Join::eval(ConstArrayRef<Value::CREF> params, Stash &stash) const { - const Value &a = lhs_tensor->eval(input, stash); - const Value &b = rhs_tensor->eval(input, stash); + const Value &a = lhs_tensor.eval(params, stash); + const Value &b = rhs_tensor.eval(params, stash); const TensorEngine &engine = infer_engine({a,b}); return engine.join(a, b, function, stash); } //----------------------------------------------------------------------------- -Node_UP inject(const ValueType &type, size_t tensor_id) { - return std::make_unique<Inject>(type, tensor_id); +const Node &inject(const ValueType &type, size_t tensor_id, Stash &stash) { + return stash.create<Inject>(type, tensor_id); } -Node_UP reduce(Node_UP tensor, Aggr aggr, const std::vector<vespalib::string> &dimensions) { - ValueType result_type = tensor->result_type.reduce(dimensions); - return std::make_unique<Reduce>(result_type, std::move(tensor), aggr, dimensions); +const Node &reduce(const Node &tensor, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) { + ValueType result_type = tensor.result_type.reduce(dimensions); + return stash.create<Reduce>(result_type, tensor, aggr, dimensions); } -Node_UP map(Node_UP tensor, map_fun_t function) { - ValueType result_type = tensor->result_type; - return std::make_unique<Map>(result_type, std::move(tensor), function); +const Node &map(const Node &tensor, map_fun_t function, Stash &stash) { + ValueType result_type = tensor.result_type; + return stash.create<Map>(result_type, tensor, function); } -Node_UP join(Node_UP lhs_tensor, Node_UP rhs_tensor, join_fun_t function) { - ValueType result_type = ValueType::join(lhs_tensor->result_type, rhs_tensor->result_type); - return std::make_unique<Join>(result_type, std::move(lhs_tensor), std::move(rhs_tensor), function); +const Node &join(const Node &lhs_tensor, const Node &rhs_tensor, join_fun_t function, Stash &stash) { + ValueType result_type = ValueType::join(lhs_tensor.result_type, rhs_tensor.result_type); + return stash.create<Join>(result_type, lhs_tensor, rhs_tensor, function); } } // namespace vespalib::eval::tensor_function diff --git a/eval/src/vespa/eval/eval/tensor_function.h b/eval/src/vespa/eval/eval/tensor_function.h index cff21b7b9aa..359cabc18a0 100644 --- a/eval/src/vespa/eval/eval/tensor_function.h +++ b/eval/src/vespa/eval/eval/tensor_function.h @@ -5,8 +5,9 @@ #include <memory> #include <vector> #include <vespa/vespalib/stllike/string.h> +#include <vespa/vespalib/util/arrayref.h> #include "value_type.h" -#include "operation.h" +#include "value.h" #include "aggr.h" namespace vespalib { @@ -15,7 +16,6 @@ class Stash; namespace eval { -class Value; class Tensor; //----------------------------------------------------------------------------- @@ -29,28 +29,19 @@ class Tensor; **/ struct TensorFunction { - typedef std::unique_ptr<TensorFunction> UP; - /** - * Interface used to obtain input to a tensor function. - **/ - struct Input { - virtual const Value &get_tensor(size_t id) const = 0; - virtual ~Input() {} - }; - - /** - * Evaluate this tensor function based on the given input. The - * given stash can be used to store temporary objects that need to - * be kept alive for the return value to be valid. The return - * value must conform to the result type indicated by the - * intermediate representation describing this tensor function. + * Evaluate this tensor function based on the given + * parameters. The given stash can be used to store temporary + * objects that need to be kept alive for the return value to be + * valid. The return value must conform to the result type + * indicated by the intermediate representation describing this + * tensor function. * * @return result of evaluating this tensor function - * @param input external stuff needed to evaluate this function + * @param params external values needed to evaluate this function + * @param stash heterogeneous object store **/ - virtual const Value &eval(const Input &input, Stash &stash) const = 0; - + virtual const Value &eval(ConstArrayRef<Value::CREF> params, Stash &stash) const = 0; virtual ~TensorFunction() {} }; @@ -78,15 +69,13 @@ using join_fun_t = double (*)(double, double); **/ struct Node : public TensorFunction { - ValueType result_type; + const ValueType result_type; Node(const ValueType &result_type_in) : result_type(result_type_in) {} - virtual void accept(TensorFunctionVisitor &visitor) const = 0; Node(const Node &) = delete; Node &operator=(const Node &) = delete; Node(Node &&) = delete; Node &operator=(Node &&) = delete; }; -using Node_UP = std::unique_ptr<Node>; /** * Simple typecasting utility. @@ -95,68 +84,53 @@ template <typename T> const T *as(const Node &node) { return dynamic_cast<const T *>(&node); } struct Inject : Node { - size_t tensor_id; + const size_t tensor_id; Inject(const ValueType &result_type_in, size_t tensor_id_in) : Node(result_type_in), tensor_id(tensor_id_in) {} - void accept(TensorFunctionVisitor &visitor) const override; - const Value &eval(const Input &input, Stash &) const override; + const Value &eval(ConstArrayRef<Value::CREF> params, Stash &) const override; }; struct Reduce : Node { - Node_UP tensor; - Aggr aggr; - std::vector<vespalib::string> dimensions; + const Node &tensor; + const Aggr aggr; + const std::vector<vespalib::string> dimensions; Reduce(const ValueType &result_type_in, - Node_UP tensor_in, + const Node &tensor_in, Aggr aggr_in, const std::vector<vespalib::string> &dimensions_in) - : Node(result_type_in), tensor(std::move(tensor_in)), aggr(aggr_in), dimensions(dimensions_in) {} - void accept(TensorFunctionVisitor &visitor) const override; - const Value &eval(const Input &input, Stash &stash) const override; + : Node(result_type_in), tensor(tensor_in), aggr(aggr_in), dimensions(dimensions_in) {} + const Value &eval(ConstArrayRef<Value::CREF> params, Stash &stash) const override; }; struct Map : Node { - Node_UP tensor; - map_fun_t function; + const Node &tensor; + const map_fun_t function; Map(const ValueType &result_type_in, - Node_UP tensor_in, + const Node &tensor_in, map_fun_t function_in) - : Node(result_type_in), tensor(std::move(tensor_in)), function(function_in) {} - void accept(TensorFunctionVisitor &visitor) const override; - const Value &eval(const Input &input, Stash &stash) const override; + : Node(result_type_in), tensor(tensor_in), function(function_in) {} + const Value &eval(ConstArrayRef<Value::CREF> params, Stash &stash) const override; }; struct Join : Node { - Node_UP lhs_tensor; - Node_UP rhs_tensor; - join_fun_t function; + const Node &lhs_tensor; + const Node &rhs_tensor; + const join_fun_t function; Join(const ValueType &result_type_in, - Node_UP lhs_tensor_in, - Node_UP rhs_tensor_in, + const Node &lhs_tensor_in, + const Node &rhs_tensor_in, join_fun_t function_in) - : Node(result_type_in), lhs_tensor(std::move(lhs_tensor_in)), - rhs_tensor(std::move(rhs_tensor_in)), function(function_in) {} - void accept(TensorFunctionVisitor &visitor) const override; - const Value &eval(const Input &input, Stash &stash) const override; + : Node(result_type_in), lhs_tensor(lhs_tensor_in), + rhs_tensor(rhs_tensor_in), function(function_in) {} + const Value &eval(ConstArrayRef<Value::CREF> params, Stash &stash) const override; }; -Node_UP inject(const ValueType &type, size_t tensor_id); -Node_UP reduce(Node_UP tensor, Aggr aggr, const std::vector<vespalib::string> &dimensions); -Node_UP map(Node_UP tensor, map_fun_t function); -Node_UP join(Node_UP lhs_tensor, Node_UP rhs_tensor, join_fun_t function); +const Node &inject(const ValueType &type, size_t tensor_id, Stash &stash); +const Node &reduce(const Node &tensor, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash); +const Node &map(const Node &tensor, map_fun_t function, Stash &stash); +const Node &join(const Node &lhs_tensor, const Node &rhs_tensor, join_fun_t function, Stash &stash); } // namespace vespalib::eval::tensor_function - -struct TensorFunctionVisitor { - virtual void visit(const tensor_function::Inject &) = 0; - virtual void visit(const tensor_function::Reduce &) = 0; - virtual void visit(const tensor_function::Map &) = 0; - virtual void visit(const tensor_function::Join &) = 0; - virtual ~TensorFunctionVisitor() {} -}; - -//----------------------------------------------------------------------------- - } // namespace vespalib::eval } // namespace vespalib diff --git a/eval/src/vespa/eval/eval/test/tensor_conformance.cpp b/eval/src/vespa/eval/eval/test/tensor_conformance.cpp index c45e2df3432..aa90cd566d5 100644 --- a/eval/src/vespa/eval/eval/test/tensor_conformance.cpp +++ b/eval/src/vespa/eval/eval/test/tensor_conformance.cpp @@ -238,20 +238,28 @@ const size_t tensor_id_a = 11; const size_t tensor_id_b = 12; // input used when evaluating in retained mode -struct Input : TensorFunction::Input { +struct Input { std::vector<Value::UP> tensors; + std::vector<Value::CREF> params; + ~Input() {} + void pad_params() { + for (size_t i = 0; i < tensor_id_a; ++i) { + params.push_back(ErrorValue::instance); + } + } Input(Value::UP a) : tensors() { + pad_params(); tensors.push_back(std::move(a)); + params.emplace_back(*tensors.back()); } Input(Value::UP a, Value::UP b) : tensors() { + pad_params(); tensors.push_back(std::move(a)); + params.emplace_back(*tensors.back()); tensors.push_back(std::move(b)); + params.emplace_back(*tensors.back()); } - const Value &get_tensor(size_t id) const override { - size_t offset = (id - tensor_id_a); - ASSERT_GREATER(tensors.size(), offset); - return *tensors[offset]; - } + ConstArrayRef<Value::CREF> get() const { return params; } }; // evaluate tensor reduce operation using tensor engine retained api @@ -264,11 +272,11 @@ struct RetainedReduce : Eval { Result eval(const TensorEngine &engine, const TensorSpec &a) const override { Stash stash; auto a_type = ValueType::from_spec(a.type()); - auto ir = tensor_function::reduce(tensor_function::inject(a_type, tensor_id_a), aggr, dimensions); - ValueType expect_type = ir->result_type; - auto fun = engine.compile(std::move(ir)); + const auto &ir = tensor_function::reduce(tensor_function::inject(a_type, tensor_id_a, stash), aggr, dimensions, stash); + ValueType expect_type = ir.result_type; + const auto &fun = engine.compile(ir, stash); Input input(engine.from_spec(a)); - return Result(engine, check_type(fun->eval(input, stash), expect_type)); + return Result(engine, check_type(fun.eval(input.get(), stash), expect_type)); } }; @@ -279,11 +287,11 @@ struct RetainedMap : Eval { Result eval(const TensorEngine &engine, const TensorSpec &a) const override { Stash stash; auto a_type = ValueType::from_spec(a.type()); - auto ir = tensor_function::map(tensor_function::inject(a_type, tensor_id_a), function); - ValueType expect_type = ir->result_type; - auto fun = engine.compile(std::move(ir)); + const auto &ir = tensor_function::map(tensor_function::inject(a_type, tensor_id_a, stash), function, stash); + ValueType expect_type = ir.result_type; + const auto &fun = engine.compile(ir, stash); Input input(engine.from_spec(a)); - return Result(engine, check_type(fun->eval(input, stash), expect_type)); + return Result(engine, check_type(fun.eval(input.get(), stash), expect_type)); } }; @@ -295,13 +303,13 @@ struct RetainedJoin : Eval { Stash stash; auto a_type = ValueType::from_spec(a.type()); auto b_type = ValueType::from_spec(b.type()); - auto ir = tensor_function::join(tensor_function::inject(a_type, tensor_id_a), - tensor_function::inject(b_type, tensor_id_b), - function); - ValueType expect_type = ir->result_type; - auto fun = engine.compile(std::move(ir)); + const auto &ir = tensor_function::join(tensor_function::inject(a_type, tensor_id_a, stash), + tensor_function::inject(b_type, tensor_id_b, stash), + function, stash); + ValueType expect_type = ir.result_type; + const auto &fun = engine.compile(ir, stash); Input input(engine.from_spec(a), engine.from_spec(b)); - return Result(engine, check_type(fun->eval(input, stash), expect_type)); + return Result(engine, check_type(fun.eval(input.get(), stash), expect_type)); } }; diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp index 9fcdfe36eba..2506e6fcf0e 100644 --- a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp +++ b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp @@ -11,6 +11,7 @@ #include <vespa/eval/eval/value.h> #include <vespa/eval/eval/tensor_spec.h> #include <vespa/eval/eval/simple_tensor_engine.h> +#include <vespa/eval/eval/operation.h> #include <cassert> @@ -21,6 +22,7 @@ using eval::Aggr; using eval::Aggregator; using eval::DoubleValue; using eval::ErrorValue; +using eval::TensorFunction; using eval::TensorSpec; using eval::Value; using eval::ValueType; @@ -93,12 +95,6 @@ const Value &fallback_reduce(const Value &a, eval::Aggr aggr, const std::vector< const DefaultTensorEngine DefaultTensorEngine::_engine; -eval::TensorFunction::UP -DefaultTensorEngine::compile(eval::tensor_function::Node_UP expr) const -{ - return DenseTensorFunctionCompiler::compile(std::move(expr)); -} - TensorSpec DefaultTensorEngine::to_spec(const Value &value) const { @@ -206,6 +202,14 @@ DefaultTensorEngine::decode(nbostream &input) const //----------------------------------------------------------------------------- +const TensorFunction & +DefaultTensorEngine::compile(const eval::tensor_function::Node &expr, Stash &stash) const +{ + return DenseTensorFunctionCompiler::compile(expr, stash); +} + +//----------------------------------------------------------------------------- + const Value & DefaultTensorEngine::map(const Value &a, map_fun_t function, Stash &stash) const { diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.h b/eval/src/vespa/eval/tensor/default_tensor_engine.h index 86ee4459902..1cef4ba2d35 100644 --- a/eval/src/vespa/eval/tensor/default_tensor_engine.h +++ b/eval/src/vespa/eval/tensor/default_tensor_engine.h @@ -19,14 +19,14 @@ private: public: static const TensorEngine &ref() { return _engine; }; - virtual eval::TensorFunction::UP compile(eval::tensor_function::Node_UP expr) const override; - TensorSpec to_spec(const Value &value) const override; Value::UP from_spec(const TensorSpec &spec) const override; void encode(const Value &value, nbostream &output) const override; Value::UP decode(nbostream &input) const override; + const TensorFunction &compile(const eval::tensor_function::Node &expr, Stash &stash) const override; + const Value &map(const Value &a, map_fun_t function, Stash &stash) const override; const Value &join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const override; const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const override; 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 530eaed9aa9..705496714fa 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 @@ -31,10 +31,10 @@ getCellsRef(const eval::Value &value) } const eval::Value & -DenseDotProductFunction::eval(const Input &input, Stash &stash) const +DenseDotProductFunction::eval(ConstArrayRef<eval::Value::CREF> params, Stash &stash) const { - DenseTensorView::CellsRef lhsCells = getCellsRef(input.get_tensor(_lhsTensorId)); - DenseTensorView::CellsRef rhsCells = getCellsRef(input.get_tensor(_rhsTensorId)); + DenseTensorView::CellsRef lhsCells = getCellsRef(params[_lhsTensorId]); + DenseTensorView::CellsRef rhsCells = getCellsRef(params[_rhsTensorId]); size_t numCells = std::min(lhsCells.size(), rhsCells.size()); double result = _hwAccelerator->dotProduct(lhsCells.cbegin(), rhsCells.cbegin(), numCells); return stash.create<eval::DoubleValue>(result); diff --git a/eval/src/vespa/eval/tensor/dense/dense_dot_product_function.h b/eval/src/vespa/eval/tensor/dense/dense_dot_product_function.h index 905939cc781..8ad57d69524 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_dot_product_function.h +++ b/eval/src/vespa/eval/tensor/dense/dense_dot_product_function.h @@ -24,7 +24,7 @@ public: DenseDotProductFunction(size_t lhsTensorId_, size_t rhsTensorId_); size_t lhsTensorId() const { return _lhsTensorId; } size_t rhsTensorId() const { return _rhsTensorId; } - virtual const eval::Value &eval(const Input &input, Stash &stash) const override; + const eval::Value &eval(ConstArrayRef<eval::Value::CREF> params, Stash &stash) const override; }; } // namespace tensor diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.cpp index a22307c25ad..e9ee7d30692 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.cpp +++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.cpp @@ -2,6 +2,7 @@ #include "dense_dot_product_function.h" #include "dense_tensor_function_compiler.h" +#include <vespa/eval/eval/operation.h> #include <vespa/vespalib/test/insertion_operators.h> #include <iostream> @@ -36,30 +37,30 @@ isCompatibleTensorsForDotProduct(const ValueType &lhsType, const ValueType &rhsT struct DotProductFunctionCompiler { - static TensorFunction::UP compile(Node_UP expr) { - const Reduce *reduce = as<Reduce>(*expr); + static const TensorFunction &compile(const Node &expr, Stash &stash) { + const Reduce *reduce = as<Reduce>(expr); if (reduce && (reduce->aggr == Aggr::SUM) && willReduceAllDimensions(reduce->dimensions)) { - const Join *join = as<Join>(*reduce->tensor); + const Join *join = as<Join>(reduce->tensor); if (join && (join->function == Mul::f)) { - const Inject *lhsTensor = as<Inject>(*join->lhs_tensor); - const Inject *rhsTensor = as<Inject>(*join->rhs_tensor); + const Inject *lhsTensor = as<Inject>(join->lhs_tensor); + const Inject *rhsTensor = as<Inject>(join->rhs_tensor); if (lhsTensor && rhsTensor && isCompatibleTensorsForDotProduct(lhsTensor->result_type, rhsTensor->result_type)) { - return std::make_unique<DenseDotProductFunction>(lhsTensor->tensor_id, rhsTensor->tensor_id); + return stash.create<DenseDotProductFunction>(lhsTensor->tensor_id, rhsTensor->tensor_id); } } } - return std::move(expr); + return expr; } }; } -TensorFunction::UP -DenseTensorFunctionCompiler::compile(Node_UP expr) +const TensorFunction & +DenseTensorFunctionCompiler::compile(const eval::tensor_function::Node &expr, Stash &stash) { - return DotProductFunctionCompiler::compile(std::move(expr)); + return DotProductFunctionCompiler::compile(expr, stash); } } // namespace tensor diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.h index ef940bf38f9..d5ba4e4f7a7 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.h +++ b/eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.h @@ -5,6 +5,9 @@ #include <vespa/eval/eval/tensor_function.h> namespace vespalib { + +class Stash; + namespace tensor { /** @@ -13,7 +16,7 @@ namespace tensor { */ struct DenseTensorFunctionCompiler { - static eval::TensorFunction::UP compile(eval::tensor_function::Node_UP expr); + static const eval::TensorFunction &compile(const eval::tensor_function::Node &expr, Stash &stash); }; } // namespace tensor |