summaryrefslogtreecommitdiffstats
path: root/eval
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2017-11-09 14:18:11 +0000
committerHåvard Pettersen <havardpe@oath.com>2017-11-09 14:18:11 +0000
commit56c26cfe5d3fd41169d928180f91d029b1295adf (patch)
tree95a77a19c31764e3984877eb516eae8444fc5713 /eval
parent9d47aad83ad4750fbfeb934c4a85abf353988974 (diff)
use const references and stash instead of UP
Diffstat (limited to 'eval')
-rw-r--r--eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp1
-rw-r--r--eval/src/tests/eval/tensor_function/tensor_function_test.cpp82
-rw-r--r--eval/src/tests/tensor/dense_dot_product_function/dense_dot_product_function_test.cpp20
-rw-r--r--eval/src/tests/tensor/dense_tensor_function_compiler/dense_tensor_function_compiler_test.cpp27
-rw-r--r--eval/src/vespa/eval/eval/interpreted_function.cpp40
-rw-r--r--eval/src/vespa/eval/eval/tensor_engine.h6
-rw-r--r--eval/src/vespa/eval/eval/tensor_function.cpp45
-rw-r--r--eval/src/vespa/eval/eval/tensor_function.h100
-rw-r--r--eval/src/vespa/eval/eval/test/tensor_conformance.cpp48
-rw-r--r--eval/src/vespa/eval/tensor/default_tensor_engine.cpp16
-rw-r--r--eval/src/vespa/eval/tensor/default_tensor_engine.h4
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_dot_product_function.cpp6
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_dot_product_function.h2
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.cpp21
-rw-r--r--eval/src/vespa/eval/tensor/dense/dense_tensor_function_compiler.h5
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 &params = 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