diff options
author | Arne H Juul <arnej27959@users.noreply.github.com> | 2021-01-18 17:04:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-18 17:04:01 +0100 |
commit | ccb0e462b5cd0d6fc8fa78ff12bfd0784a29202e (patch) | |
tree | 4f5586730915ccf2e898af04838697a8cc4e5c0f /eval | |
parent | 4346f876a996980f16921e1e47cb2fe7d3dfb7d5 (diff) | |
parent | 2c083d9c7d6e4b4b30e119e8fe0af573962c7120 (diff) |
Merge pull request #16066 from vespa-engine/arnej/forward-index-for-mixed-rename
Arnej/forward index for mixed rename
Diffstat (limited to 'eval')
29 files changed, 386 insertions, 292 deletions
diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt index 7aad02bb67a..00618f2c838 100644 --- a/eval/CMakeLists.txt +++ b/eval/CMakeLists.txt @@ -53,11 +53,11 @@ vespa_define_module( src/tests/instruction/dense_tensor_peek_function src/tests/instruction/index_lookup_table src/tests/instruction/join_with_number - src/tests/instruction/dense_add_dimension_optimizer - src/tests/instruction/dense_fast_rename_optimizer + src/tests/instruction/add_trivial_dimension_optimizer + src/tests/instruction/fast_rename_optimizer src/tests/instruction/dense_inplace_join_function src/tests/instruction/dense_pow_as_map_optimizer - src/tests/instruction/dense_remove_dimension_optimizer + src/tests/instruction/remove_trivial_dimension_optimizer src/tests/instruction/dense_replace_type_function src/tests/instruction/dense_simple_join_function src/tests/instruction/dense_simple_map_function diff --git a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp index 7094686e399..23bd16cb721 100644 --- a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp +++ b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp @@ -4,10 +4,10 @@ #include <vespa/eval/eval/tensor_function.h> #include <vespa/eval/eval/simple_value.h> #include <vespa/eval/eval/fast_value.h> -#include <vespa/eval/instruction/dense_replace_type_function.h> +#include <vespa/eval/instruction/replace_type_function.h> #include <vespa/eval/instruction/dense_cell_range_function.h> #include <vespa/eval/instruction/dense_lambda_peek_function.h> -#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> +#include <vespa/eval/instruction/fast_rename_optimizer.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> #include <vespa/eval/eval/tensor_nodes.h> @@ -62,7 +62,7 @@ void verify_generic(const vespalib::string &expr, const vespalib::string &expect } void verify_reshape(const vespalib::string &expr, const vespalib::string &expect) { - verify_impl<DenseReplaceTypeFunction>(expr, expect); + verify_impl<ReplaceTypeFunction>(expr, expect); } void verify_range(const vespalib::string &expr, const vespalib::string &expect) { diff --git a/eval/src/tests/instruction/add_trivial_dimension_optimizer/CMakeLists.txt b/eval/src/tests/instruction/add_trivial_dimension_optimizer/CMakeLists.txt new file mode 100644 index 00000000000..70d2209da5c --- /dev/null +++ b/eval/src/tests/instruction/add_trivial_dimension_optimizer/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(eval_add_trivial_dimension_optimizer_test_app TEST + SOURCES + add_trivial_dimension_optimizer_test.cpp + DEPENDS + vespaeval +) +vespa_add_test(NAME eval_add_trivial_dimension_optimizer_test_app COMMAND eval_add_trivial_dimension_optimizer_test_app) diff --git a/eval/src/tests/instruction/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp b/eval/src/tests/instruction/add_trivial_dimension_optimizer/add_trivial_dimension_optimizer_test.cpp index e7660ce8933..35195522adc 100644 --- a/eval/src/tests/instruction/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp +++ b/eval/src/tests/instruction/add_trivial_dimension_optimizer/add_trivial_dimension_optimizer_test.cpp @@ -3,8 +3,8 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/fast_value.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/instruction/dense_replace_type_function.h> -#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> +#include <vespa/eval/instruction/replace_type_function.h> +#include <vespa/eval/instruction/fast_rename_optimizer.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> @@ -31,14 +31,14 @@ EvalFixture::ParamRepo param_repo = make_params(); void verify_optimized(const vespalib::string &expr) { EvalFixture fixture(prod_factory, expr, param_repo, true); EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo)); - auto info = fixture.find_all<DenseReplaceTypeFunction>(); + auto info = fixture.find_all<ReplaceTypeFunction>(); EXPECT_EQUAL(info.size(), 1u); } void verify_not_optimized(const vespalib::string &expr) { EvalFixture fixture(prod_factory, expr, param_repo, true); EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo)); - auto info = fixture.find_all<DenseReplaceTypeFunction>(); + auto info = fixture.find_all<ReplaceTypeFunction>(); EXPECT_TRUE(info.empty()); } @@ -80,9 +80,9 @@ TEST("require that dimension addition with overlapping dimensions is optimized") TEST_DO(verify_optimized("tensor(y[1],z[1])(1)*x5y1")); } -TEST("require that dimension addition with inappropriate dimensions is not optimized") { - TEST_DO(verify_not_optimized("x_m*tensor(y[1])(1)")); - TEST_DO(verify_not_optimized("tensor(y[1])(1)*x_m")); +TEST("require that dimension addition with mixed dimensions is optimized") { + TEST_DO(verify_optimized("x_m*tensor(y[1])(1)")); + TEST_DO(verify_optimized("tensor(y[1])(1)*x_m")); } TEST("require that dimension addition optimization requires unit constant tensor") { diff --git a/eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt deleted file mode 100644 index 1bc9f93b1a2..00000000000 --- a/eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(eval_dense_add_dimension_optimizer_test_app TEST - SOURCES - dense_add_dimension_optimizer_test.cpp - DEPENDS - vespaeval -) -vespa_add_test(NAME eval_dense_add_dimension_optimizer_test_app COMMAND eval_dense_add_dimension_optimizer_test_app) diff --git a/eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt deleted file mode 100644 index 32cf6c45d1e..00000000000 --- a/eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(eval_dense_fast_rename_optimizer_test_app TEST - SOURCES - dense_fast_rename_optimizer_test.cpp - DEPENDS - vespaeval -) -vespa_add_test(NAME eval_dense_fast_rename_optimizer_test_app COMMAND eval_dense_fast_rename_optimizer_test_app) diff --git a/eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp b/eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp deleted file mode 100644 index 043c8814c72..00000000000 --- a/eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/instruction/dense_replace_type_function.h> -#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> -#include <vespa/eval/eval/test/tensor_model.hpp> -#include <vespa/eval/eval/test/eval_fixture.h> - -#include <vespa/vespalib/util/stringfmt.h> -#include <vespa/vespalib/util/stash.h> - -using namespace vespalib; -using namespace vespalib::eval; -using namespace vespalib::eval::test; -using namespace vespalib::eval::tensor_function; - -const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); - -EvalFixture::ParamRepo make_params() { - return EvalFixture::ParamRepo() - .add("x5", spec({x(5)}, N())) - .add("x5f", spec(float_cells({x(5)}), N())) - .add("x_m", spec({x({"a", "b", "c"})}, N())) - .add("x5y3", spec({x(5),y(3)}, N())); -} -EvalFixture::ParamRepo param_repo = make_params(); - -void verify_optimized(const vespalib::string &expr) { - EvalFixture fixture(prod_factory, expr, param_repo, true); - EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo)); - auto info = fixture.find_all<DenseReplaceTypeFunction>(); - EXPECT_EQUAL(info.size(), 1u); -} - -void verify_not_optimized(const vespalib::string &expr) { - EvalFixture fixture(prod_factory, expr, param_repo, true); - EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo)); - auto info = fixture.find_all<DenseReplaceTypeFunction>(); - EXPECT_TRUE(info.empty()); -} - -TEST("require that non-transposing dense renames are optimized") { - TEST_DO(verify_optimized("rename(x5,x,y)")); - TEST_DO(verify_optimized("rename(x5,x,a)")); - TEST_DO(verify_optimized("rename(x5y3,y,z)")); - TEST_DO(verify_optimized("rename(x5y3,x,a)")); - TEST_DO(verify_optimized("rename(x5y3,(x,y),(a,b))")); - TEST_DO(verify_optimized("rename(x5y3,(x,y),(z,zz))")); - TEST_DO(verify_optimized("rename(x5y3,(x,y),(y,z))")); - TEST_DO(verify_optimized("rename(x5y3,(y,x),(b,a))")); -} - -TEST("require that transposing dense renames are not optimized") { - TEST_DO(verify_not_optimized("rename(x5y3,x,z)")); - TEST_DO(verify_not_optimized("rename(x5y3,y,a)")); - TEST_DO(verify_not_optimized("rename(x5y3,(x,y),(y,x))")); - TEST_DO(verify_not_optimized("rename(x5y3,(x,y),(b,a))")); - TEST_DO(verify_not_optimized("rename(x5y3,(y,x),(a,b))")); -} - -TEST("require that non-dense renames are not optimized") { - TEST_DO(verify_not_optimized("rename(x_m,x,y)")); -} - -TEST("require that chained optimized renames are compacted into a single operation") { - TEST_DO(verify_optimized("rename(rename(x5,x,y),y,z)")); -} - -TEST("require that optimization works for float cells") { - TEST_DO(verify_optimized("rename(x5f,x,y)")); -} - -TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt deleted file mode 100644 index c945bd31609..00000000000 --- a/eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(eval_dense_remove_dimension_optimizer_test_app TEST - SOURCES - dense_remove_dimension_optimizer_test.cpp - DEPENDS - vespaeval -) -vespa_add_test(NAME eval_dense_remove_dimension_optimizer_test_app COMMAND eval_dense_remove_dimension_optimizer_test_app) diff --git a/eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp b/eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp index 6b8e6faecf4..988ca79a04a 100644 --- a/eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp +++ b/eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp @@ -4,7 +4,7 @@ #include <vespa/eval/eval/fast_value.h> #include <vespa/eval/eval/value_codec.h> #include <vespa/eval/eval/interpreted_function.h> -#include <vespa/eval/instruction/dense_replace_type_function.h> +#include <vespa/eval/instruction/replace_type_function.h> #include <vespa/eval/eval/test/tensor_model.hpp> using namespace vespalib::eval::tensor_function; @@ -29,7 +29,7 @@ struct Fixture { Value::UP my_value; ValueType new_type; ChildMock mock_child; - DenseReplaceTypeFunction my_fun; + ReplaceTypeFunction my_fun; std::vector<TensorFunction::Child::CREF> children; InterpretedFunction::State state; Fixture() @@ -49,7 +49,7 @@ struct Fixture { } }; -TEST_F("require that DenseReplaceTypeFunction works as expected", Fixture()) { +TEST_F("require that ReplaceTypeFunction works as expected", Fixture()) { EXPECT_EQUAL(f1.my_fun.result_type(), f1.new_type); EXPECT_EQUAL(f1.my_fun.result_is_mutable(), true); f1.mock_child.is_mutable = false; @@ -65,8 +65,8 @@ TEST("require that create_compact will collapse duplicate replace operations") { Stash stash; ValueType type = ValueType::double_type(); ChildMock leaf(type); - const DenseReplaceTypeFunction &a = DenseReplaceTypeFunction::create_compact(type, leaf, stash); - const DenseReplaceTypeFunction &b = DenseReplaceTypeFunction::create_compact(type, a, stash); + const ReplaceTypeFunction &a = ReplaceTypeFunction::create_compact(type, leaf, stash); + const ReplaceTypeFunction &b = ReplaceTypeFunction::create_compact(type, a, stash); EXPECT_EQUAL(a.result_type(), type); EXPECT_EQUAL(&a.child(), &leaf); EXPECT_EQUAL(b.result_type(), type); diff --git a/eval/src/tests/instruction/fast_rename_optimizer/CMakeLists.txt b/eval/src/tests/instruction/fast_rename_optimizer/CMakeLists.txt new file mode 100644 index 00000000000..a69f26f6a85 --- /dev/null +++ b/eval/src/tests/instruction/fast_rename_optimizer/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(eval_fast_rename_optimizer_test_app TEST + SOURCES + fast_rename_optimizer_test.cpp + DEPENDS + vespaeval +) +vespa_add_test(NAME eval_fast_rename_optimizer_test_app COMMAND eval_fast_rename_optimizer_test_app) diff --git a/eval/src/tests/instruction/fast_rename_optimizer/fast_rename_optimizer_test.cpp b/eval/src/tests/instruction/fast_rename_optimizer/fast_rename_optimizer_test.cpp new file mode 100644 index 00000000000..dc90a5e54a1 --- /dev/null +++ b/eval/src/tests/instruction/fast_rename_optimizer/fast_rename_optimizer_test.cpp @@ -0,0 +1,129 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/eval/eval/tensor_function.h> +#include <vespa/eval/instruction/replace_type_function.h> +#include <vespa/eval/instruction/fast_rename_optimizer.h> +#include <vespa/eval/eval/test/tensor_model.hpp> +#include <vespa/eval/eval/test/eval_fixture.h> + +#include <vespa/vespalib/util/stringfmt.h> +#include <vespa/vespalib/util/stash.h> + +using namespace vespalib; +using namespace vespalib::eval; +using namespace vespalib::eval::test; +using namespace vespalib::eval::tensor_function; + +const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); + +EvalFixture::ParamRepo make_params() { + return EvalFixture::ParamRepo() + .add("x5", spec({x(5)}, N())) + .add("x5f", spec(float_cells({x(5)}), N())) + .add("x_m", spec({x({"a", "b", "c"})}, N())) + .add("xy_mm", spec({x({"a", "b", "c"}),y({"d","e"})}, N())) + .add("x5y3z_m", spec({x(5),y(3),z({"a","b"})}, N())) + .add("x5yz_m", spec({x(5),y({"a","b"}),z({"d","e"})}, N())) + .add("x5y3", spec({x(5),y(3)}, N())); +} +EvalFixture::ParamRepo param_repo = make_params(); + +void verify_optimized(const vespalib::string &expr) { + EvalFixture fixture(prod_factory, expr, param_repo, true); + EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo)); + auto info = fixture.find_all<ReplaceTypeFunction>(); + EXPECT_EQUAL(info.size(), 1u); +} + +void verify_not_optimized(const vespalib::string &expr) { + EvalFixture fixture(prod_factory, expr, param_repo, true); + EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo)); + auto info = fixture.find_all<ReplaceTypeFunction>(); + EXPECT_TRUE(info.empty()); +} + +TEST("require that non-transposing dense renames are optimized") { + TEST_DO(verify_optimized("rename(x5,x,y)")); + TEST_DO(verify_optimized("rename(x5,x,a)")); + TEST_DO(verify_optimized("rename(x5y3,y,z)")); + TEST_DO(verify_optimized("rename(x5y3,x,a)")); + TEST_DO(verify_optimized("rename(x5y3,(x,y),(a,b))")); + TEST_DO(verify_optimized("rename(x5y3,(x,y),(z,zz))")); + TEST_DO(verify_optimized("rename(x5y3,(x,y),(y,z))")); + TEST_DO(verify_optimized("rename(x5y3,(y,x),(b,a))")); +} + +TEST("require that transposing dense renames are not optimized") { + TEST_DO(verify_not_optimized("rename(x5y3,x,z)")); + TEST_DO(verify_not_optimized("rename(x5y3,y,a)")); + TEST_DO(verify_not_optimized("rename(x5y3,(x,y),(y,x))")); + TEST_DO(verify_not_optimized("rename(x5y3,(x,y),(b,a))")); + TEST_DO(verify_not_optimized("rename(x5y3,(y,x),(a,b))")); +} + +TEST("require that non-dense renames may be optimized") { + TEST_DO(verify_optimized("rename(x_m,x,y)")); + TEST_DO(verify_optimized("rename(xy_mm,(x,y),(a,b))")); + TEST_DO(verify_optimized("rename(xy_mm,(x,y),(y,z))")); + TEST_DO(verify_not_optimized("rename(xy_mm,(x,y),(b,a))")); + TEST_DO(verify_not_optimized("rename(xy_mm,(x,y),(y,x))")); + + TEST_DO(verify_optimized("rename(x5y3z_m,(z),(a))")); + TEST_DO(verify_optimized("rename(x5y3z_m,(x,y,z),(b,c,a))")); + TEST_DO(verify_optimized("rename(x5y3z_m,(z),(a))")); + TEST_DO(verify_optimized("rename(x5y3z_m,(x,y,z),(b,c,a))")); + TEST_DO(verify_not_optimized("rename(x5y3z_m,(y),(a))")); + TEST_DO(verify_not_optimized("rename(x5y3z_m,(x,z),(z,x))")); + + TEST_DO(verify_optimized("rename(x5yz_m,(x,y),(y,x))")); + TEST_DO(verify_optimized("rename(x5yz_m,(x,y,z),(c,a,b))")); + TEST_DO(verify_optimized("rename(x5yz_m,(y,z),(a,b))")); + TEST_DO(verify_not_optimized("rename(x5yz_m,(z),(a))")); + TEST_DO(verify_not_optimized("rename(x5yz_m,(y,z),(z,y))")); +} + +TEST("require that chained optimized renames are compacted into a single operation") { + TEST_DO(verify_optimized("rename(rename(x5,x,y),y,z)")); +} + +TEST("require that optimization works for float cells") { + TEST_DO(verify_optimized("rename(x5f,x,y)")); +} + +bool is_stable(const vespalib::string &from_spec, const vespalib::string &to_spec, + const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to) +{ + auto from_type = ValueType::from_spec(from_spec); + auto to_type = ValueType::from_spec(to_spec); + return FastRenameOptimizer::is_stable_rename(from_type, to_type, from, to); +} + +TEST("require that rename is stable if dimension order is preserved") { + EXPECT_TRUE(is_stable("tensor(a{},b{})", "tensor(a{},c{})", {"b"}, {"c"})); + EXPECT_TRUE(is_stable("tensor(c[3],d[5])", "tensor(c[3],e[5])", {"d"}, {"e"})); + EXPECT_TRUE(is_stable("tensor(a{},b{},c[3],d[5])", "tensor(a{},b{},c[3],e[5])", {"d"}, {"e"})); + EXPECT_TRUE(is_stable("tensor(a{},b{},c[3],d[5])", "tensor(e{},f{},g[3],h[5])", {"a", "b", "c", "d"}, {"e", "f", "g", "h"})); +} + +TEST("require that rename is unstable if nontrivial indexed dimensions change order") { + EXPECT_FALSE(is_stable("tensor(c[3],d[5])", "tensor(d[5],e[3])", {"c"}, {"e"})); + EXPECT_FALSE(is_stable("tensor(c[3],d[5])", "tensor(c[5],d[3])", {"c", "d"}, {"d", "c"})); +} + +TEST("require that rename is unstable if mapped dimensions change order") { + EXPECT_FALSE(is_stable("tensor(a{},b{})", "tensor(b{},c{})", {"a"}, {"c"})); + EXPECT_FALSE(is_stable("tensor(a{},b{})", "tensor(a{},b{})", {"a", "b"}, {"b", "a"})); +} + +TEST("require that rename can be stable if indexed and mapped dimensions change order") { + EXPECT_TRUE(is_stable("tensor(a{},b{},c[3],d[5])", "tensor(a[3],b[5],c{},d{})", {"a", "b", "c", "d"}, {"c", "d", "a", "b"})); + EXPECT_TRUE(is_stable("tensor(a{},b{},c[3],d[5])", "tensor(c[3],d[5],e{},f{})", {"a", "b"}, {"e", "f"})); +} + +TEST("require that rename can be stable if trivial dimension is moved") { + EXPECT_TRUE(is_stable("tensor(a[1],b{},c[3])", "tensor(b{},bb[1],c[3])", {"a"}, {"bb"})); + EXPECT_TRUE(is_stable("tensor(a[1],b{},c[3])", "tensor(b{},c[3],cc[1])", {"a"}, {"cc"})); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/eval/src/tests/instruction/remove_trivial_dimension_optimizer/CMakeLists.txt b/eval/src/tests/instruction/remove_trivial_dimension_optimizer/CMakeLists.txt new file mode 100644 index 00000000000..a23a97ca856 --- /dev/null +++ b/eval/src/tests/instruction/remove_trivial_dimension_optimizer/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(eval_remove_trivial_dimension_optimizer_test_app TEST + SOURCES + remove_trivial_dimension_optimizer_test.cpp + DEPENDS + vespaeval +) +vespa_add_test(NAME eval_remove_trivial_dimension_optimizer_test_app COMMAND eval_remove_trivial_dimension_optimizer_test_app) diff --git a/eval/src/tests/instruction/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp b/eval/src/tests/instruction/remove_trivial_dimension_optimizer/remove_trivial_dimension_optimizer_test.cpp index 4c3c86be7f8..4de7e85074d 100644 --- a/eval/src/tests/instruction/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp +++ b/eval/src/tests/instruction/remove_trivial_dimension_optimizer/remove_trivial_dimension_optimizer_test.cpp @@ -2,8 +2,8 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/instruction/dense_replace_type_function.h> -#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> +#include <vespa/eval/instruction/replace_type_function.h> +#include <vespa/eval/instruction/fast_rename_optimizer.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> @@ -29,14 +29,14 @@ EvalFixture::ParamRepo param_repo = make_params(); void verify_optimized(const vespalib::string &expr) { EvalFixture fixture(prod_factory, expr, param_repo, true); EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo)); - auto info = fixture.find_all<DenseReplaceTypeFunction>(); + auto info = fixture.find_all<ReplaceTypeFunction>(); EXPECT_EQUAL(info.size(), 1u); } void verify_not_optimized(const vespalib::string &expr) { EvalFixture fixture(prod_factory, expr, param_repo, true); EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo)); - auto info = fixture.find_all<DenseReplaceTypeFunction>(); + auto info = fixture.find_all<ReplaceTypeFunction>(); EXPECT_TRUE(info.empty()); } @@ -68,8 +68,9 @@ TEST("require that full reduce is not optimized") { TEST_DO(verify_not_optimized("reduce(x1y1z1,sum,x,y,z)")); } -TEST("require that inappropriate tensor types cannot be optimized") { - TEST_DO(verify_not_optimized("reduce(x1y5z_m,sum,x)")); +TEST("require that mixed tensor types can be optimized") { + TEST_DO(verify_optimized("reduce(x1y5z_m,sum,x)")); + TEST_DO(verify_not_optimized("reduce(x1y5z_m,sum,y)")); TEST_DO(verify_not_optimized("reduce(x1y5z_m,sum,z)")); } diff --git a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp index cbd4192a84f..515b48b3693 100644 --- a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp +++ b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp @@ -8,10 +8,10 @@ #include <vespa/eval/instruction/dense_xw_product_function.h> #include <vespa/eval/instruction/dense_matmul_function.h> #include <vespa/eval/instruction/dense_multi_matmul_function.h> -#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> -#include <vespa/eval/instruction/dense_add_dimension_optimizer.h> +#include <vespa/eval/instruction/fast_rename_optimizer.h> +#include <vespa/eval/instruction/add_trivial_dimension_optimizer.h> #include <vespa/eval/instruction/dense_single_reduce_function.h> -#include <vespa/eval/instruction/dense_remove_dimension_optimizer.h> +#include <vespa/eval/instruction/remove_trivial_dimension_optimizer.h> #include <vespa/eval/instruction/dense_lambda_peek_optimizer.h> #include <vespa/eval/instruction/dense_simple_expand_function.h> #include <vespa/eval/instruction/dense_simple_join_function.h> @@ -58,13 +58,13 @@ const TensorFunction &optimize_for_factory(const ValueBuilderFactory &factory, c while (!nodes.empty()) { const Child &child = nodes.back().get(); child.set(DenseSimpleExpandFunction::optimize(child.get(), stash)); - child.set(DenseAddDimensionOptimizer::optimize(child.get(), stash)); - child.set(DenseRemoveDimensionOptimizer::optimize(child.get(), stash)); + child.set(AddTrivialDimensionOptimizer::optimize(child.get(), stash)); + child.set(RemoveTrivialDimensionOptimizer::optimize(child.get(), stash)); child.set(VectorFromDoublesFunction::optimize(child.get(), stash)); child.set(DenseTensorCreateFunction::optimize(child.get(), stash)); child.set(DenseTensorPeekFunction::optimize(child.get(), stash)); child.set(DenseLambdaPeekOptimizer::optimize(child.get(), stash)); - child.set(DenseFastRenameOptimizer::optimize(child.get(), stash)); + child.set(FastRenameOptimizer::optimize(child.get(), stash)); child.set(DensePowAsMapOptimizer::optimize(child.get(), stash)); child.set(DenseSimpleMapFunction::optimize(child.get(), stash)); child.set(DenseSimpleJoinFunction::optimize(child.get(), stash)); diff --git a/eval/src/vespa/eval/instruction/CMakeLists.txt b/eval/src/vespa/eval/instruction/CMakeLists.txt index 42f88c0ee52..1317a2c2cf6 100644 --- a/eval/src/vespa/eval/instruction/CMakeLists.txt +++ b/eval/src/vespa/eval/instruction/CMakeLists.txt @@ -2,15 +2,23 @@ vespa_add_library(eval_instruction OBJECT SOURCES + add_trivial_dimension_optimizer.cpp dense_cell_range_function.cpp dense_dot_product_function.cpp dense_lambda_peek_function.cpp dense_lambda_peek_optimizer.cpp dense_matmul_function.cpp dense_multi_matmul_function.cpp + dense_pow_as_map_optimizer.cpp + remove_trivial_dimension_optimizer.cpp dense_simple_expand_function.cpp + dense_simple_join_function.cpp + dense_simple_map_function.cpp + dense_single_reduce_function.cpp + dense_tensor_create_function.cpp dense_tensor_peek_function.cpp dense_xw_product_function.cpp + fast_rename_optimizer.cpp generic_concat.cpp generic_create.cpp generic_join.cpp @@ -22,14 +30,6 @@ vespa_add_library(eval_instruction OBJECT generic_rename.cpp index_lookup_table.cpp join_with_number_function.cpp - dense_add_dimension_optimizer.cpp - dense_fast_rename_optimizer.cpp - dense_pow_as_map_optimizer.cpp - dense_remove_dimension_optimizer.cpp - dense_replace_type_function.cpp - dense_simple_join_function.cpp - dense_simple_map_function.cpp - dense_single_reduce_function.cpp - dense_tensor_create_function.cpp + replace_type_function.cpp vector_from_doubles_function.cpp ) diff --git a/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.cpp b/eval/src/vespa/eval/instruction/add_trivial_dimension_optimizer.cpp index ccccb595c6d..110ff197d1b 100644 --- a/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.cpp +++ b/eval/src/vespa/eval/instruction/add_trivial_dimension_optimizer.cpp @@ -1,7 +1,7 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "dense_add_dimension_optimizer.h" -#include "dense_replace_type_function.h" +#include "add_trivial_dimension_optimizer.h" +#include "replace_type_function.h" #include <vespa/eval/eval/operation.h> #include <vespa/eval/eval/wrap_param.h> @@ -20,6 +20,9 @@ bool same_cell_type(const TensorFunction &a, const TensorFunction &b) { } bool is_unit_constant(const TensorFunction &node) { + if (! node.result_type().is_dense()) { + return false; + } if (auto const_value = as<ConstValue>(node)) { for (const auto &dim: node.result_type().dimensions()) { if (dim.size != 1) { @@ -34,20 +37,17 @@ bool is_unit_constant(const TensorFunction &node) { } // namespace vespalib::eval::<unnamed> const TensorFunction & -DenseAddDimensionOptimizer::optimize(const TensorFunction &expr, Stash &stash) +AddTrivialDimensionOptimizer::optimize(const TensorFunction &expr, Stash &stash) { if (auto join = as<Join>(expr)) { const TensorFunction &lhs = join->lhs(); const TensorFunction &rhs = join->rhs(); - if ((join->function() == Mul::f) && - lhs.result_type().is_dense() && - rhs.result_type().is_dense()) - { + if (join->function() == Mul::f) { if (is_unit_constant(lhs) && same_cell_type(rhs, expr)) { - return DenseReplaceTypeFunction::create_compact(expr.result_type(), rhs, stash); + return ReplaceTypeFunction::create_compact(expr.result_type(), rhs, stash); } if (is_unit_constant(rhs) && same_cell_type(lhs, expr)) { - return DenseReplaceTypeFunction::create_compact(expr.result_type(), lhs, stash); + return ReplaceTypeFunction::create_compact(expr.result_type(), lhs, stash); } } } diff --git a/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.h b/eval/src/vespa/eval/instruction/add_trivial_dimension_optimizer.h index 99ab20614a2..ab0e6af71f7 100644 --- a/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.h +++ b/eval/src/vespa/eval/instruction/add_trivial_dimension_optimizer.h @@ -8,10 +8,9 @@ namespace vespalib::eval { /** * Tensor function optimizer for efficient adding of dimensions with - * size 1 for dense tensors. - * TODO: extend to mixed tensors. + * known size 1. **/ -struct DenseAddDimensionOptimizer { +struct AddTrivialDimensionOptimizer { static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp deleted file mode 100644 index a4ef32f4701..00000000000 --- a/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "dense_fast_rename_optimizer.h" -#include "dense_replace_type_function.h" -#include <vespa/eval/eval/value.h> - -namespace vespalib::eval { - -using namespace tensor_function; - -namespace { - -bool is_dense_stable_rename(const ValueType &from_type, const ValueType &to_type, - const std::vector<vespalib::string> &from, - const std::vector<vespalib::string> &to) -{ - if (!from_type.is_dense() || - !to_type.is_dense() || - (from.size() != to.size())) - { - return false; - } - size_t npos = ValueType::Dimension::npos; - for (size_t i = 0; i < from.size(); ++i) { - size_t old_idx = from_type.dimension_index(from[i]); - size_t new_idx = to_type.dimension_index(to[i]); - if ((old_idx != new_idx) || (old_idx == npos)) { - return false; - } - } - return true; -} - -} // namespace vespalib::eval::<unnamed> - -const TensorFunction & -DenseFastRenameOptimizer::optimize(const TensorFunction &expr, Stash &stash) -{ - if (auto rename = as<Rename>(expr)) { - const ValueType &from_type = rename->child().result_type(); - const ValueType &to_type = expr.result_type(); - if (is_dense_stable_rename(from_type, to_type, rename->from(), rename->to())) { - assert(to_type.cell_type() == from_type.cell_type()); - return DenseReplaceTypeFunction::create_compact(to_type, rename->child(), stash); - } - } - return expr; -} - -} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp index f8ce886ae1f..39b2bed4017 100644 --- a/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp +++ b/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp @@ -3,7 +3,7 @@ #include "dense_lambda_peek_optimizer.h" #include "dense_lambda_peek_function.h" #include "dense_cell_range_function.h" -#include <vespa/eval/instruction/dense_replace_type_function.h> +#include <vespa/eval/instruction/replace_type_function.h> #include <vespa/eval/eval/value.h> #include <vespa/eval/eval/node_tools.h> #include <vespa/eval/eval/basic_nodes.h> @@ -182,7 +182,7 @@ DenseLambdaPeekOptimizer::optimize(const TensorFunction &expr, Stash &stash) if (result.cell_range && (dst_type.cell_type() == src_type.cell_type())) { auto cell_range = result.cell_range.value(); if (cell_range.is_full(src_type.dense_subspace_size())) { - return DenseReplaceTypeFunction::create_compact(dst_type, get_param, stash); + return ReplaceTypeFunction::create_compact(dst_type, get_param, stash); } else { return stash.create<DenseCellRangeFunction>(dst_type, get_param, cell_range.offset, cell_range.length); diff --git a/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp b/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp deleted file mode 100644 index 81d3ca67880..00000000000 --- a/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "dense_replace_type_function.h" -#include <vespa/eval/eval/value.h> - -namespace vespalib::eval { - -using namespace tensor_function; - -namespace { - -void my_replace_type_op(InterpretedFunction::State &state, uint64_t param) { - const ValueType &type = unwrap_param<ValueType>(param); - TypedCells cells = state.peek(0).cells(); - state.pop_push(state.stash.create<DenseValueView>(type, cells)); -} - -} // namespace vespalib::eval::<unnamed> - -DenseReplaceTypeFunction::DenseReplaceTypeFunction(const ValueType &result_type, - const TensorFunction &child) - : tensor_function::Op1(result_type, child) -{ -} - -DenseReplaceTypeFunction::~DenseReplaceTypeFunction() -{ -} - -InterpretedFunction::Instruction -DenseReplaceTypeFunction::compile_self(const ValueBuilderFactory &, Stash &) const -{ - return InterpretedFunction::Instruction(my_replace_type_op, wrap_param<ValueType>(result_type())); -} - -const DenseReplaceTypeFunction & -DenseReplaceTypeFunction::create_compact(const ValueType &result_type, - const TensorFunction &child, - Stash &stash) -{ - if (auto replace = as<DenseReplaceTypeFunction>(child)) { - return stash.create<DenseReplaceTypeFunction>(result_type, replace->child()); - } else { - return stash.create<DenseReplaceTypeFunction>(result_type, child); - } -} - -} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/dense_replace_type_function.h b/eval/src/vespa/eval/instruction/dense_replace_type_function.h deleted file mode 100644 index 78ce163aceb..00000000000 --- a/eval/src/vespa/eval/instruction/dense_replace_type_function.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#pragma once - -#include <vespa/eval/eval/tensor_function.h> - -namespace vespalib::eval { - -/** - * Tensor function for efficient type-only modification of dense - * tensor. - * TODO: extend to handling any tensor, dense/mixed/sparse. - **/ -class DenseReplaceTypeFunction : public tensor_function::Op1 -{ -public: - DenseReplaceTypeFunction(const ValueType &result_type, - const TensorFunction &child); - ~DenseReplaceTypeFunction(); - InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; - bool result_is_mutable() const override { return child().result_is_mutable(); } - static const DenseReplaceTypeFunction &create_compact(const ValueType &result_type, - const TensorFunction &child, - Stash &stash); -}; - -} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/fast_rename_optimizer.cpp b/eval/src/vespa/eval/instruction/fast_rename_optimizer.cpp new file mode 100644 index 00000000000..4b9de9307a9 --- /dev/null +++ b/eval/src/vespa/eval/instruction/fast_rename_optimizer.cpp @@ -0,0 +1,63 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "fast_rename_optimizer.h" +#include "replace_type_function.h" +#include <vespa/eval/eval/value.h> +#include <optional> + +namespace vespalib::eval { + +using namespace tensor_function; + +bool +FastRenameOptimizer::is_stable_rename(const ValueType &from_type, const ValueType &to_type, + const std::vector<vespalib::string> &from, + const std::vector<vespalib::string> &to) +{ + assert(from.size() == to.size()); + auto get_from_idx = [&](const vespalib::string &to_name) { + for (size_t i = 0; i < to.size(); ++i) { + if (to[i] == to_name) { + return from_type.dimension_index(from[i]); + } + } + return from_type.dimension_index(to_name); + }; + std::optional<size_t> prev_mapped; + std::optional<size_t> prev_indexed; + const auto &from_dims = from_type.dimensions(); + for (const auto &to_dim: to_type.dimensions()) { + size_t from_idx = get_from_idx(to_dim.name); + assert(from_idx != ValueType::Dimension::npos); + if (to_dim.is_mapped()) { + assert(from_dims[from_idx].is_mapped()); + if (prev_mapped && (prev_mapped.value() > from_idx)) { + return false; + } + prev_mapped = from_idx; + } else if (!to_dim.is_trivial()) { + assert(from_dims[from_idx].is_indexed()); + if (prev_indexed && (prev_indexed.value() > from_idx)) { + return false; + } + prev_indexed = from_idx; + } + } + return true; +} + +const TensorFunction & +FastRenameOptimizer::optimize(const TensorFunction &expr, Stash &stash) +{ + if (auto rename = as<Rename>(expr)) { + const ValueType &from_type = rename->child().result_type(); + const ValueType &to_type = expr.result_type(); + if (is_stable_rename(from_type, to_type, rename->from(), rename->to())) { + assert(to_type.cell_type() == from_type.cell_type()); + return ReplaceTypeFunction::create_compact(to_type, rename->child(), stash); + } + } + return expr; +} + +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.h b/eval/src/vespa/eval/instruction/fast_rename_optimizer.h index 2882cdf6f30..11bf6c27f74 100644 --- a/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.h +++ b/eval/src/vespa/eval/instruction/fast_rename_optimizer.h @@ -7,11 +7,12 @@ namespace vespalib::eval { /** - * Tensor function optimizer for efficient non-transposing rename of a - * dense tensor. - * TODO: extend to mixed tensors. + * Tensor function optimizer for efficient non-transposing renames. **/ -struct DenseFastRenameOptimizer { +struct FastRenameOptimizer { + static bool is_stable_rename(const ValueType &from_type, const ValueType &to_type, + const std::vector<vespalib::string> &from, + const std::vector<vespalib::string> &to); static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/generic_rename.cpp b/eval/src/vespa/eval/instruction/generic_rename.cpp index b6f51a79fc3..4fe347375c4 100644 --- a/eval/src/vespa/eval/instruction/generic_rename.cpp +++ b/eval/src/vespa/eval/instruction/generic_rename.cpp @@ -101,8 +101,32 @@ void my_generic_rename_op(State &state, uint64_t param_in) { state.pop_push(result_ref); } +template <typename CT> +void my_mixed_rename_dense_only_op(State &state, uint64_t param_in) { + const auto ¶m = unwrap_param<RenameParam>(param_in); + const DenseRenamePlan &dense_plan = param.dense_plan; + const auto &index = state.peek(0).index(); + auto lhs_cells = state.peek(0).cells().typify<CT>(); + size_t num_subspaces = index.size(); + size_t num_out_cells = dense_plan.subspace_size * num_subspaces; + ArrayRef<CT> out_cells = state.stash.create_uninitialized_array<CT>(num_out_cells); + CT *dst = out_cells.begin(); + const CT *lhs = lhs_cells.begin(); + auto copy_cells = [&](size_t input_idx) { *dst++ = lhs[input_idx]; }; + for (size_t i = 0; i < num_subspaces; ++i) { + dense_plan.execute(0, copy_cells); + lhs += dense_plan.subspace_size; + } + assert(lhs == lhs_cells.end()); + assert(dst == out_cells.end()); + state.pop_push(state.stash.create<ValueView>(param.res_type, index, TypedCells(out_cells))); +} + struct SelectGenericRenameOp { - template <typename CT> static auto invoke() { + template <typename CT> static auto invoke(const RenameParam ¶m) { + if (param.sparse_plan.can_forward_index) { + return my_mixed_rename_dense_only_op<CT>; + } return my_generic_rename_op<CT>; } }; @@ -115,7 +139,7 @@ SparseRenamePlan::SparseRenamePlan(const ValueType &input_type, const ValueType &output_type, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to) - : output_dimensions() + : output_dimensions(), can_forward_index(true) { const auto in_dims = input_type.mapped_dimensions(); const auto out_dims = output_type.mapped_dimensions(); @@ -125,6 +149,9 @@ SparseRenamePlan::SparseRenamePlan(const ValueType &input_type, const auto & renamed_to = find_rename(dim.name, from, to); size_t index = find_index_of(renamed_to, out_dims); assert(index < mapped_dims); + if (index != output_dimensions.size()) { + can_forward_index = false; + } output_dimensions.push_back(index); } assert(output_dimensions.size() == mapped_dims); @@ -182,7 +209,7 @@ GenericRename::make_instruction(const ValueType &lhs_type, auto ¶m = stash.create<RenameParam>(lhs_type, rename_dimension_from, rename_dimension_to, factory); - auto fun = typify_invoke<1,TypifyCellType,SelectGenericRenameOp>(param.res_type.cell_type()); + auto fun = typify_invoke<1,TypifyCellType,SelectGenericRenameOp>(param.res_type.cell_type(), param); return Instruction(fun, wrap_param<RenameParam>(param)); } diff --git a/eval/src/vespa/eval/instruction/generic_rename.h b/eval/src/vespa/eval/instruction/generic_rename.h index 6c94ff02b24..7834c967488 100644 --- a/eval/src/vespa/eval/instruction/generic_rename.h +++ b/eval/src/vespa/eval/instruction/generic_rename.h @@ -29,6 +29,7 @@ struct DenseRenamePlan { struct SparseRenamePlan { size_t mapped_dims; std::vector<size_t> output_dimensions; + bool can_forward_index; SparseRenamePlan(const ValueType &input_type, const ValueType &output_type, const std::vector<vespalib::string> &from, diff --git a/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.cpp b/eval/src/vespa/eval/instruction/remove_trivial_dimension_optimizer.cpp index fc7f31fb421..77f5247aaaa 100644 --- a/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.cpp +++ b/eval/src/vespa/eval/instruction/remove_trivial_dimension_optimizer.cpp @@ -1,7 +1,7 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "dense_remove_dimension_optimizer.h" -#include "dense_replace_type_function.h" +#include "remove_trivial_dimension_optimizer.h" +#include "replace_type_function.h" #include <vespa/eval/eval/value_type.h> namespace vespalib::eval { @@ -24,17 +24,16 @@ bool is_trivial_dim_list(const ValueType &type, const std::vector<vespalib::stri } // namespace vespalib::eval::<unnamed> const TensorFunction & -DenseRemoveDimensionOptimizer::optimize(const TensorFunction &expr, Stash &stash) +RemoveTrivialDimensionOptimizer::optimize(const TensorFunction &expr, Stash &stash) { if (auto reduce = as<Reduce>(expr)) { const TensorFunction &child = reduce->child(); - if (expr.result_type().is_dense() && - child.result_type().is_dense() && + if ((! expr.result_type().dimensions().empty()) && aggr::is_ident(reduce->aggr()) && is_trivial_dim_list(child.result_type(), reduce->dimensions())) { assert(expr.result_type().cell_type() == child.result_type().cell_type()); - return DenseReplaceTypeFunction::create_compact(expr.result_type(), child, stash); + return ReplaceTypeFunction::create_compact(expr.result_type(), child, stash); } } return expr; diff --git a/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.h b/eval/src/vespa/eval/instruction/remove_trivial_dimension_optimizer.h index 2b4e3588caf..be1de0e0628 100644 --- a/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.h +++ b/eval/src/vespa/eval/instruction/remove_trivial_dimension_optimizer.h @@ -8,10 +8,9 @@ namespace vespalib::eval { /** * Tensor function optimizer for efficient removal of dimensions with - * size 1 for dense tensors. - * TODO: extend to mixed tensors. + * known size 1. **/ -struct DenseRemoveDimensionOptimizer { +struct RemoveTrivialDimensionOptimizer { static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/replace_type_function.cpp b/eval/src/vespa/eval/instruction/replace_type_function.cpp new file mode 100644 index 00000000000..d319f2378bb --- /dev/null +++ b/eval/src/vespa/eval/instruction/replace_type_function.cpp @@ -0,0 +1,49 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "replace_type_function.h" +#include <vespa/eval/eval/value.h> + +namespace vespalib::eval { + +using namespace tensor_function; + +namespace { + +void my_replace_type_op(InterpretedFunction::State &state, uint64_t param) { + const ValueType &type = unwrap_param<ValueType>(param); + TypedCells cells = state.peek(0).cells(); + const auto & idx = state.peek(0).index(); + state.pop_push(state.stash.create<ValueView>(type, idx, cells)); +} + +} // namespace vespalib::eval::<unnamed> + +ReplaceTypeFunction::ReplaceTypeFunction(const ValueType &result_type, + const TensorFunction &child) + : tensor_function::Op1(result_type, child) +{ +} + +ReplaceTypeFunction::~ReplaceTypeFunction() +{ +} + +InterpretedFunction::Instruction +ReplaceTypeFunction::compile_self(const ValueBuilderFactory &, Stash &) const +{ + return InterpretedFunction::Instruction(my_replace_type_op, wrap_param<ValueType>(result_type())); +} + +const ReplaceTypeFunction & +ReplaceTypeFunction::create_compact(const ValueType &result_type, + const TensorFunction &child, + Stash &stash) +{ + if (auto replace = as<ReplaceTypeFunction>(child)) { + return stash.create<ReplaceTypeFunction>(result_type, replace->child()); + } else { + return stash.create<ReplaceTypeFunction>(result_type, child); + } +} + +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/replace_type_function.h b/eval/src/vespa/eval/instruction/replace_type_function.h new file mode 100644 index 00000000000..a4feb93cfbc --- /dev/null +++ b/eval/src/vespa/eval/instruction/replace_type_function.h @@ -0,0 +1,25 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <vespa/eval/eval/tensor_function.h> + +namespace vespalib::eval { + +/** + * Tensor function for efficient type-only modification of values. + **/ +class ReplaceTypeFunction : public tensor_function::Op1 +{ +public: + ReplaceTypeFunction(const ValueType &result_type, + const TensorFunction &child); + ~ReplaceTypeFunction(); + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; + bool result_is_mutable() const override { return child().result_is_mutable(); } + static const ReplaceTypeFunction &create_compact(const ValueType &result_type, + const TensorFunction &child, + Stash &stash); +}; + +} // namespace vespalib::eval |