diff options
author | Håvard Pettersen <havardpe@oath.com> | 2017-10-26 10:29:38 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2017-10-26 10:37:04 +0000 |
commit | a1bf89afb2845ca3a560ec4fa693a4f55dca8c6e (patch) | |
tree | 5c5ba4d86f02bca06224d8c9ac23f22a37a9058f | |
parent | 5173775ac89edc765835c4fc8ac6a77383fc4c6e (diff) |
remove TensorSum (use more generic TensorReduce instead)
17 files changed, 36 insertions, 156 deletions
diff --git a/eval/src/tests/eval/compiled_function/compiled_function_test.cpp b/eval/src/tests/eval/compiled_function/compiled_function_test.cpp index 357baa4d5c5..b887c6e45f9 100644 --- a/eval/src/tests/eval/compiled_function/compiled_function_test.cpp +++ b/eval/src/tests/eval/compiled_function/compiled_function_test.cpp @@ -49,7 +49,6 @@ TEST("require that lazy parameter passing works") { //----------------------------------------------------------------------------- std::vector<vespalib::string> unsupported = { - "sum(", "map(", "join(", "reduce(", diff --git a/eval/src/tests/eval/function/function_test.cpp b/eval/src/tests/eval/function/function_test.cpp index 621f68ffc62..eae58b04178 100644 --- a/eval/src/tests/eval/function/function_test.cpp +++ b/eval/src/tests/eval/function/function_test.cpp @@ -750,15 +750,9 @@ TEST("require that missing value gives parse error") { //----------------------------------------------------------------------------- -TEST("require that tensor sum can be parsed") { - EXPECT_EQUAL("sum(a)", Function::parse("sum(a)").dump()); - EXPECT_EQUAL("sum(a)", Function::parse(" sum ( a ) ").dump()); - EXPECT_EQUAL("sum(a,dim)", Function::parse("sum(a,dim)").dump()); - EXPECT_EQUAL("sum(a,dim)", Function::parse(" sum ( a , dim ) ").dump()); -} - TEST("require that tensor operations can be nested") { - EXPECT_EQUAL("sum(sum(sum(a)),dim)", Function::parse("sum(sum(sum(a)),dim)").dump()); + EXPECT_EQUAL("reduce(reduce(reduce(a,sum),sum),sum,dim)", + Function::parse("reduce(reduce(reduce(a,sum),sum),sum,dim)").dump()); } //----------------------------------------------------------------------------- @@ -795,6 +789,7 @@ TEST("require that tensor reduce can be parsed") { EXPECT_EQUAL("reduce(x,sum,a,b)", Function::parse({"x"}, "reduce(x,sum,a,b)").dump()); EXPECT_EQUAL("reduce(x,sum,a,b,c)", Function::parse({"x"}, "reduce(x,sum,a,b,c)").dump()); EXPECT_EQUAL("reduce(x,sum,a,b,c)", Function::parse({"x"}, " reduce ( x , sum , a , b , c ) ").dump()); + EXPECT_EQUAL("reduce(x,sum)", Function::parse({"x"}, "reduce(x,sum)").dump()); EXPECT_EQUAL("reduce(x,avg)", Function::parse({"x"}, "reduce(x,avg)").dump()); EXPECT_EQUAL("reduce(x,avg)", Function::parse({"x"}, "reduce( x , avg )").dump()); EXPECT_EQUAL("reduce(x,count)", Function::parse({"x"}, "reduce(x,count)").dump()); @@ -803,11 +798,6 @@ TEST("require that tensor reduce can be parsed") { EXPECT_EQUAL("reduce(x,max)", Function::parse({"x"}, "reduce(x,max)").dump()); } -TEST("require that tensor reduce is mapped to tensor sum for all dimensions/single dimension") { - EXPECT_EQUAL("sum(x)", Function::parse({"x"}, "reduce(x,sum)").dump()); - EXPECT_EQUAL("sum(x,d)", Function::parse({"x"}, "reduce(x,sum,d)").dump()); -} - TEST("require that tensor reduce with unknown aggregator fails") { verify_error("reduce(x,bogus)", "[reduce(x,bogus]...[unknown aggregator: 'bogus']...[)]"); } 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 9aeb28a17b1..fb31601bf0f 100644 --- a/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp +++ b/eval/src/tests/eval/interpreted_function/interpreted_function_test.cpp @@ -143,7 +143,7 @@ TEST("require that basic addition works") { TEST("require that dot product like expression is not optimized for unknown types") { const TensorEngine &engine = SimpleTensorEngine::ref(); - Function function = Function::parse("sum(a*b)"); + Function function = Function::parse("reduce(a*b,sum)"); DoubleValue a(2.0); DoubleValue b(3.0); double expect = (2.0 * 3.0); @@ -158,7 +158,7 @@ TEST("require that dot product like expression is not optimized for unknown type TEST("require that dot product works with tensor function") { const TensorEngine &engine = SimpleTensorEngine::ref(); - Function function = Function::parse("sum(a*b)"); + Function function = Function::parse("reduce(a*b,sum)"); auto a = TensorSpec("tensor(x[3])") .add({{"x", 0}}, 5.0) .add({{"x", 1}}, 3.0) @@ -182,7 +182,7 @@ TEST("require that dot product works with tensor function") { TEST("require that matrix multiplication works with tensor function") { const TensorEngine &engine = SimpleTensorEngine::ref(); - Function function = Function::parse("sum(a*b,y)"); + Function function = Function::parse("reduce(a*b,sum,y)"); auto a = TensorSpec("tensor(x[2],y[2])") .add({{"x", 0},{"y", 0}}, 1.0) .add({{"x", 0},{"y", 1}}, 2.0) diff --git a/eval/src/tests/eval/node_types/node_types_test.cpp b/eval/src/tests/eval/node_types/node_types_test.cpp index 555c2bd2ba4..f6afa543402 100644 --- a/eval/src/tests/eval/node_types/node_types_test.cpp +++ b/eval/src/tests/eval/node_types/node_types_test.cpp @@ -129,23 +129,6 @@ TEST("require that set membership resolves to double unless error") { TEST_DO(verify("any in [tensor,error,any]", "error")); } -TEST("require that sum resolves correct type") { - TEST_DO(verify("sum(error)", "error")); - TEST_DO(verify("sum(tensor)", "double")); - TEST_DO(verify("sum(double)", "double")); - TEST_DO(verify("sum(any)", "any")); -} - -TEST("require that dimension sum resolves correct type") { - TEST_DO(verify("sum(error,x)", "error")); - TEST_DO(verify("sum(tensor,x)", "any")); - TEST_DO(verify("sum(any,x)", "any")); - TEST_DO(verify("sum(double,x)", "error")); - TEST_DO(verify("sum(tensor(x{},y{},z{}),y)", "tensor(x{},z{})")); - TEST_DO(verify("sum(tensor(x{},y{},z{}),w)", "error")); - TEST_DO(verify("sum(tensor(x{}),x)", "double")); -} - TEST("require that reduce resolves correct type") { TEST_DO(verify("reduce(error,sum)", "error")); TEST_DO(verify("reduce(tensor,sum)", "double")); @@ -291,7 +274,7 @@ TEST("require that tensor concat resolves correct type") { TEST("require that double only expressions can be detected") { Function plain_fun = Function::parse("1+2"); - Function complex_fun = Function::parse("sum(a)"); + Function complex_fun = Function::parse("reduce(a,sum)"); NodeTypes plain_types(plain_fun, {}); NodeTypes complex_types(complex_fun, {ValueType::tensor_type({})}); EXPECT_TRUE(plain_types.get_type(plain_fun.root()).is_double()); diff --git a/eval/src/tests/tensor/tensor_performance/tensor_performance_test.cpp b/eval/src/tests/tensor/tensor_performance/tensor_performance_test.cpp index 735e9c9ab34..3daaa3f79b3 100644 --- a/eval/src/tests/tensor/tensor_performance/tensor_performance_test.cpp +++ b/eval/src/tests/tensor/tensor_performance/tensor_performance_test.cpp @@ -18,10 +18,10 @@ using namespace vespalib::tensor; //----------------------------------------------------------------------------- -const vespalib::string dot_product_match_expr = "sum(query*document)"; -const vespalib::string dot_product_multiply_expr = "sum(query*document)"; -const vespalib::string model_match_expr = "sum((query*document)*model)"; -const vespalib::string matrix_product_expr = "sum(sum((query+document)*model,x))"; +const vespalib::string dot_product_match_expr = "reduce(query*document,sum)"; +const vespalib::string dot_product_multiply_expr = "reduce(query*document,sum)"; +const vespalib::string model_match_expr = "reduce((query*document)*model,sum)"; +const vespalib::string matrix_product_expr = "reduce(reduce((query+document)*model,sum,x),sum)"; //----------------------------------------------------------------------------- diff --git a/eval/src/vespa/eval/eval/function.cpp b/eval/src/vespa/eval/eval/function.cpp index cb3d157c06f..58d61d33ea6 100644 --- a/eval/src/vespa/eval/eval/function.cpp +++ b/eval/src/vespa/eval/eval/function.cpp @@ -587,13 +587,7 @@ void parse_tensor_reduce(ParseContext &ctx) { return; } auto dimensions = get_ident_list(ctx, false); - if ((*maybe_aggr == Aggr::SUM) && dimensions.empty()) { - ctx.push_expression(std::make_unique<nodes::TensorSum>(std::move(child))); - } else if ((*maybe_aggr == Aggr::SUM) && (dimensions.size() == 1)) { - ctx.push_expression(std::make_unique<nodes::TensorSum>(std::move(child), dimensions[0])); - } else { - ctx.push_expression(std::make_unique<nodes::TensorReduce>(std::move(child), *maybe_aggr, std::move(dimensions))); - } + ctx.push_expression(std::make_unique<nodes::TensorReduce>(std::move(child), *maybe_aggr, std::move(dimensions))); } void parse_tensor_rename(ParseContext &ctx) { @@ -648,20 +642,6 @@ void parse_tensor_concat(ParseContext &ctx) { ctx.push_expression(std::make_unique<nodes::TensorConcat>(std::move(lhs), std::move(rhs), dimension)); } -// to be replaced with more generic 'reduce' -void parse_tensor_sum(ParseContext &ctx) { - parse_expression(ctx); - Node_UP child = ctx.pop_expression(); - if (ctx.get() == ',') { - ctx.next(); - vespalib::string dimension = get_ident(ctx, false); - ctx.skip_spaces(); - ctx.push_expression(Node_UP(new nodes::TensorSum(std::move(child), dimension))); - } else { - ctx.push_expression(Node_UP(new nodes::TensorSum(std::move(child)))); - } -} - bool try_parse_call(ParseContext &ctx, const vespalib::string &name) { ctx.skip_spaces(); if (ctx.get() == '(') { @@ -686,8 +666,6 @@ bool try_parse_call(ParseContext &ctx, const vespalib::string &name) { parse_tensor_lambda(ctx); } else if (name == "concat") { parse_tensor_concat(ctx); - } else if (name == "sum") { - parse_tensor_sum(ctx); } else { ctx.fail(make_string("unknown function: '%s'", name.c_str())); return false; diff --git a/eval/src/vespa/eval/eval/interpreted_function.cpp b/eval/src/vespa/eval/eval/interpreted_function.cpp index e6e11dbd7c3..a397370c28e 100644 --- a/eval/src/vespa/eval/eval/interpreted_function.cpp +++ b/eval/src/vespa/eval/eval/interpreted_function.cpp @@ -101,17 +101,6 @@ void op_not_member(State &state, uint64_t) { //----------------------------------------------------------------------------- -void op_tensor_sum(State &state, uint64_t) { - state.replace(1, state.engine.reduce(state.peek(0), Aggr::SUM, {}, state.stash)); -} - -void op_tensor_sum_dimension(State &state, uint64_t param) { - const vespalib::string &dimension = unwrap_param<vespalib::string>(param); - state.replace(1, state.engine.reduce(state.peek(0), Aggr::SUM, {dimension}, state.stash)); -} - -//----------------------------------------------------------------------------- - void op_tensor_map(State &state, uint64_t param) { const CompiledFunction &cfun = unwrap_param<CompiledFunction>(param); state.replace(1, state.engine.map(state.peek(0), cfun.get_function<1>(), state.stash)); @@ -270,44 +259,34 @@ struct ProgramBuilder : public NodeVisitor, public NodeTraverser { void visit(const Error &) override { program.emplace_back(op_load_const, wrap_param<Value>(stash.create<ErrorValue>())); } - void visit(const TensorSum&node) override { - if (is_typed(node) && is_typed_tensor_product_of_params(node.get_child(0))) { + void visit(const TensorMap&node) override { + const auto &token = stash.create<CompileCache::Token::UP>(CompileCache::compile(node.lambda(), PassParams::SEPARATE)); + program.emplace_back(op_tensor_map, wrap_param<CompiledFunction>(token.get()->get())); + } + void visit(const TensorJoin&node) override { + const auto &token = stash.create<CompileCache::Token::UP>(CompileCache::compile(node.lambda(), PassParams::SEPARATE)); + program.emplace_back(op_tensor_join, wrap_param<CompiledFunction>(token.get()->get())); + } + void visit(const TensorReduce&node) override { + if ((node.aggr() == Aggr::SUM) && is_typed(node) && is_typed_tensor_product_of_params(node.get_child(0))) { assert(program.size() >= 3); // load,load,mul program.pop_back(); // mul program.pop_back(); // load program.pop_back(); // load - std::vector<vespalib::string> dim_list; - if (!node.dimension().empty()) { - dim_list.push_back(node.dimension()); - } 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), Aggr::SUM, dim_list); + 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()); program.emplace_back(op_tensor_function_arg_arg, wrap_param<TensorFunctionArgArgMeta>(meta)); - } else if (node.dimension().empty()) { - program.emplace_back(op_tensor_sum); } else { - program.emplace_back(op_tensor_sum_dimension, - wrap_param<vespalib::string>(stash.create<vespalib::string>(node.dimension()))); + ReduceParams ¶ms = stash.create<ReduceParams>(node.aggr(), node.dimensions()); + program.emplace_back(op_tensor_reduce, wrap_param<ReduceParams>(params)); } } - void visit(const TensorMap&node) override { - const auto &token = stash.create<CompileCache::Token::UP>(CompileCache::compile(node.lambda(), PassParams::SEPARATE)); - program.emplace_back(op_tensor_map, wrap_param<CompiledFunction>(token.get()->get())); - } - void visit(const TensorJoin&node) override { - const auto &token = stash.create<CompileCache::Token::UP>(CompileCache::compile(node.lambda(), PassParams::SEPARATE)); - program.emplace_back(op_tensor_join, wrap_param<CompiledFunction>(token.get()->get())); - } - void visit(const TensorReduce&node) override { - ReduceParams ¶ms = stash.create<ReduceParams>(node.aggr(), node.dimensions()); - program.emplace_back(op_tensor_reduce, wrap_param<ReduceParams>(params)); - } void visit(const TensorRename&node) override { RenameParams ¶ms = stash.create<RenameParams>(node.from(), node.to()); program.emplace_back(op_tensor_rename, wrap_param<RenameParams>(params)); diff --git a/eval/src/vespa/eval/eval/key_gen.cpp b/eval/src/vespa/eval/eval/key_gen.cpp index 65be8d172fd..490f1c044ac 100644 --- a/eval/src/vespa/eval/eval/key_gen.cpp +++ b/eval/src/vespa/eval/eval/key_gen.cpp @@ -31,7 +31,6 @@ struct KeyGen : public NodeVisitor, public NodeTraverser { void visit(const If &node) override { add_byte( 7); add_double(node.p_true()); } void visit(const Let &) override { add_byte( 8); } void visit(const Error &) override { add_byte( 9); } - void visit(const TensorSum &) override { add_byte(10); } // dimensions should be part of key void visit(const TensorMap &) override { add_byte(11); } // lambda should be part of key void visit(const TensorJoin &) override { add_byte(12); } // lambda should be part of key void visit(const TensorReduce &) override { add_byte(13); } // aggr/dimensions should be part of key diff --git a/eval/src/vespa/eval/eval/llvm/compiled_function.cpp b/eval/src/vespa/eval/eval/llvm/compiled_function.cpp index fc016f6a1fd..a696f16f849 100644 --- a/eval/src/vespa/eval/eval/llvm/compiled_function.cpp +++ b/eval/src/vespa/eval/eval/llvm/compiled_function.cpp @@ -123,8 +123,7 @@ CompiledFunction::detect_issues(const Function &function) std::vector<vespalib::string> issues; bool open(const nodes::Node &) override { return true; } void close(const nodes::Node &node) override { - if (nodes::check_type<nodes::TensorSum, - nodes::TensorMap, + if (nodes::check_type<nodes::TensorMap, nodes::TensorJoin, nodes::TensorReduce, nodes::TensorRename, diff --git a/eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp b/eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp index 30c10464a35..77e23b44799 100644 --- a/eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp +++ b/eval/src/vespa/eval/eval/llvm/llvm_wrapper.cpp @@ -415,9 +415,6 @@ struct FunctionBuilder : public NodeVisitor, public NodeTraverser { // tensor nodes (not supported in compiled expressions) - void visit(const TensorSum &node) override { - make_error(node.num_children()); - } void visit(const TensorMap &node) override { make_error(node.num_children()); } diff --git a/eval/src/vespa/eval/eval/node_types.cpp b/eval/src/vespa/eval/eval/node_types.cpp index 24dd6196d64..3e942c7284e 100644 --- a/eval/src/vespa/eval/eval/node_types.cpp +++ b/eval/src/vespa/eval/eval/node_types.cpp @@ -152,14 +152,6 @@ struct TypeResolver : public NodeVisitor, public NodeTraverser { void visit(const Error &node) override { bind_type(ValueType::error_type(), node); } - void visit(const TensorSum &node) override { - const ValueType &child = state.peek(0); - if (node.dimension().empty()) { - bind_type(child.reduce({}), node); - } else { - bind_type(child.reduce({node.dimension()}), node); - } - } void visit(const TensorMap &node) override { resolve_op1(node); } void visit(const TensorJoin &node) override { resolve_op2(node); } void visit(const TensorReduce &node) override { diff --git a/eval/src/vespa/eval/eval/node_visitor.h b/eval/src/vespa/eval/eval/node_visitor.h index 1bbcef24107..b12689e9603 100644 --- a/eval/src/vespa/eval/eval/node_visitor.h +++ b/eval/src/vespa/eval/eval/node_visitor.h @@ -30,7 +30,6 @@ struct NodeVisitor { virtual void visit(const nodes::Error &) = 0; // tensor nodes - virtual void visit(const nodes::TensorSum &) = 0; virtual void visit(const nodes::TensorMap &) = 0; virtual void visit(const nodes::TensorJoin &) = 0; virtual void visit(const nodes::TensorReduce &) = 0; @@ -91,16 +90,15 @@ struct NodeVisitor { * of all types not specifically handled. **/ struct EmptyNodeVisitor : NodeVisitor { - virtual void visit(const nodes::Number &) override {} - virtual void visit(const nodes::Symbol &) override {} - virtual void visit(const nodes::String &) override {} - virtual void visit(const nodes::Array &) override {} - virtual void visit(const nodes::Neg &) override {} - virtual void visit(const nodes::Not &) override {} - virtual void visit(const nodes::If &) override {} - virtual void visit(const nodes::Let &) override {} + void visit(const nodes::Number &) override {} + void visit(const nodes::Symbol &) override {} + void visit(const nodes::String &) override {} + void visit(const nodes::Array &) override {} + void visit(const nodes::Neg &) override {} + void visit(const nodes::Not &) override {} + void visit(const nodes::If &) override {} + void visit(const nodes::Let &) override {} void visit(const nodes::Error &) override {} - void visit(const nodes::TensorSum &) override {} void visit(const nodes::TensorMap &) override {} void visit(const nodes::TensorJoin &) override {} void visit(const nodes::TensorReduce &) override {} diff --git a/eval/src/vespa/eval/eval/tensor_nodes.cpp b/eval/src/vespa/eval/eval/tensor_nodes.cpp index ea468b463ff..6abcd8fb9bc 100644 --- a/eval/src/vespa/eval/eval/tensor_nodes.cpp +++ b/eval/src/vespa/eval/eval/tensor_nodes.cpp @@ -7,7 +7,6 @@ namespace vespalib { namespace eval { namespace nodes { -void TensorSum ::accept(NodeVisitor &visitor) const { visitor.visit(*this); } void TensorMap ::accept(NodeVisitor &visitor) const { visitor.visit(*this); } void TensorJoin ::accept(NodeVisitor &visitor) const { visitor.visit(*this); } void TensorReduce::accept(NodeVisitor &visitor) const { visitor.visit(*this); } diff --git a/eval/src/vespa/eval/eval/tensor_nodes.h b/eval/src/vespa/eval/eval/tensor_nodes.h index df686510c1a..bfa572f1d94 100644 --- a/eval/src/vespa/eval/eval/tensor_nodes.h +++ b/eval/src/vespa/eval/eval/tensor_nodes.h @@ -12,38 +12,6 @@ namespace vespalib { namespace eval { namespace nodes { -class TensorSum : public Node { -private: - Node_UP _child; - vespalib::string _dimension; -public: - TensorSum(Node_UP child) : _child(std::move(child)), _dimension() {} - TensorSum(Node_UP child, const vespalib::string &dimension_in) - : _child(std::move(child)), _dimension(dimension_in) {} - const vespalib::string &dimension() const { return _dimension; } - vespalib::string dump(DumpContext &ctx) const override { - vespalib::string str; - str += "sum("; - str += _child->dump(ctx); - if (!_dimension.empty()) { - str += ","; - str += _dimension; - } - str += ")"; - return str; - } - void accept(NodeVisitor &visitor) const override; - size_t num_children() const override { return 1; } - const Node &get_child(size_t idx) const override { - (void) idx; - assert(idx == 0); - return *_child; - } - void detach_children(NodeHandler &handler) override { - handler.handle(std::move(_child)); - } -}; - class TensorMap : public Node { private: Node_UP _child; diff --git a/eval/src/vespa/eval/eval/test/eval_spec.cpp b/eval/src/vespa/eval/eval/test/eval_spec.cpp index f9c36c9eb93..086e6570e0a 100644 --- a/eval/src/vespa/eval/eval/test/eval_spec.cpp +++ b/eval/src/vespa/eval/eval/test/eval_spec.cpp @@ -166,7 +166,6 @@ EvalSpec::add_function_call_cases() { void EvalSpec::add_tensor_operation_cases() { - add_rule({"a", -1.0, 1.0}, "sum(a)", [](double a){ return a; }); add_rule({"a", -1.0, 1.0}, "map(a,f(x)(sin(x)))", [](double x){ return std::sin(x); }); add_rule({"a", -1.0, 1.0}, "map(a,f(x)(x+x*3))", [](double x){ return (x + (x * 3)); }); add_rule({"a", -1.0, 1.0}, {"b", -1.0, 1.0}, "join(a,b,f(x,y)(x+y))", [](double x, double y){ return (x + y); }); diff --git a/eval/src/vespa/eval/eval/test/tensor_conformance.cpp b/eval/src/vespa/eval/eval/test/tensor_conformance.cpp index fc6a5006e82..3c8cc505bd6 100644 --- a/eval/src/vespa/eval/eval/test/tensor_conformance.cpp +++ b/eval/src/vespa/eval/eval/test/tensor_conformance.cpp @@ -833,7 +833,7 @@ struct TestContext { const TensorSpec &lhs, const TensorSpec &rhs) { - Expr_TT eval("sum(a*b)"); + Expr_TT eval("reduce(a*b,sum)"); TEST_DO(verify_result(safe(eval).eval(engine, lhs, rhs), spec(expect))); } diff --git a/searchlib/src/tests/features/prod_features.cpp b/searchlib/src/tests/features/prod_features.cpp index b1524cea904..345c66ec672 100644 --- a/searchlib/src/tests/features/prod_features.cpp +++ b/searchlib/src/tests/features/prod_features.cpp @@ -1837,7 +1837,7 @@ Test::testRankingExpression() } { // test interpreted expression - vespalib::string my_expr("3.0 + value(4.0) + sum(tensorFromWeightedSet(query(my_tensor)))"); + vespalib::string my_expr("3.0 + value(4.0) + reduce(tensorFromWeightedSet(query(my_tensor)),sum)"); FtFeatureTest ft(_factory, getExpression(my_expr)); ft.getQueryEnv().getProperties().add("my_tensor", "{a:1,b:2,c:3}"); ASSERT_TRUE(ft.setup()); |