aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArne H Juul <arnej27959@users.noreply.github.com>2021-01-18 17:04:01 +0100
committerGitHub <noreply@github.com>2021-01-18 17:04:01 +0100
commitccb0e462b5cd0d6fc8fa78ff12bfd0784a29202e (patch)
tree4f5586730915ccf2e898af04838697a8cc4e5c0f
parent4346f876a996980f16921e1e47cb2fe7d3dfb7d5 (diff)
parent2c083d9c7d6e4b4b30e119e8fe0af573962c7120 (diff)
Merge pull request #16066 from vespa-engine/arnej/forward-index-for-mixed-rename
Arnej/forward index for mixed rename
-rw-r--r--eval/CMakeLists.txt6
-rw-r--r--eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp6
-rw-r--r--eval/src/tests/instruction/add_trivial_dimension_optimizer/CMakeLists.txt8
-rw-r--r--eval/src/tests/instruction/add_trivial_dimension_optimizer/add_trivial_dimension_optimizer_test.cpp (renamed from eval/src/tests/instruction/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp)14
-rw-r--r--eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt8
-rw-r--r--eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt8
-rw-r--r--eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp74
-rw-r--r--eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt8
-rw-r--r--eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp10
-rw-r--r--eval/src/tests/instruction/fast_rename_optimizer/CMakeLists.txt8
-rw-r--r--eval/src/tests/instruction/fast_rename_optimizer/fast_rename_optimizer_test.cpp129
-rw-r--r--eval/src/tests/instruction/remove_trivial_dimension_optimizer/CMakeLists.txt8
-rw-r--r--eval/src/tests/instruction/remove_trivial_dimension_optimizer/remove_trivial_dimension_optimizer_test.cpp (renamed from eval/src/tests/instruction/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp)13
-rw-r--r--eval/src/vespa/eval/eval/optimize_tensor_function.cpp12
-rw-r--r--eval/src/vespa/eval/instruction/CMakeLists.txt18
-rw-r--r--eval/src/vespa/eval/instruction/add_trivial_dimension_optimizer.cpp (renamed from eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.cpp)18
-rw-r--r--eval/src/vespa/eval/instruction/add_trivial_dimension_optimizer.h (renamed from eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.h)5
-rw-r--r--eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp50
-rw-r--r--eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp4
-rw-r--r--eval/src/vespa/eval/instruction/dense_replace_type_function.cpp48
-rw-r--r--eval/src/vespa/eval/instruction/dense_replace_type_function.h27
-rw-r--r--eval/src/vespa/eval/instruction/fast_rename_optimizer.cpp63
-rw-r--r--eval/src/vespa/eval/instruction/fast_rename_optimizer.h (renamed from eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.h)9
-rw-r--r--eval/src/vespa/eval/instruction/generic_rename.cpp33
-rw-r--r--eval/src/vespa/eval/instruction/generic_rename.h1
-rw-r--r--eval/src/vespa/eval/instruction/remove_trivial_dimension_optimizer.cpp (renamed from eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.cpp)11
-rw-r--r--eval/src/vespa/eval/instruction/remove_trivial_dimension_optimizer.h (renamed from eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.h)5
-rw-r--r--eval/src/vespa/eval/instruction/replace_type_function.cpp49
-rw-r--r--eval/src/vespa/eval/instruction/replace_type_function.h25
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 &param = 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 &param) {
+ 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 &param = 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