summaryrefslogtreecommitdiffstats
path: root/eval
diff options
context:
space:
mode:
authorArne Juul <arnej@verizonmedia.com>2020-09-24 13:32:33 +0000
committerArne Juul <arnej@verizonmedia.com>2020-09-24 13:47:06 +0000
commit34f461e913a40db6db18e5d98a3ef9e8880de0cb (patch)
treef0c6afc10570e9dc1127dc4b5373d49d9d267f34 /eval
parente7596b401ac579b1be0ed54183f64bfdc3d591bf (diff)
move generic join into its own files
Diffstat (limited to 'eval')
-rw-r--r--eval/CMakeLists.txt1
-rw-r--r--eval/src/tests/eval/simple_value/simple_value_test.cpp48
-rw-r--r--eval/src/tests/instruction/generic_join/CMakeLists.txt9
-rw-r--r--eval/src/tests/instruction/generic_join/generic_join_test.cpp119
-rw-r--r--eval/src/tests/instruction/generic_rename/generic_rename_test.cpp7
-rw-r--r--eval/src/vespa/eval/eval/CMakeLists.txt2
-rw-r--r--eval/src/vespa/eval/eval/tensor_instructions.h24
-rw-r--r--eval/src/vespa/eval/eval/tensor_plans.cpp86
-rw-r--r--eval/src/vespa/eval/instruction/CMakeLists.txt1
-rw-r--r--eval/src/vespa/eval/instruction/generic_join.cpp (renamed from eval/src/vespa/eval/eval/tensor_instructions.cpp)114
-rw-r--r--eval/src/vespa/eval/instruction/generic_join.h (renamed from eval/src/vespa/eval/eval/tensor_plans.h)22
11 files changed, 252 insertions, 181 deletions
diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt
index cb0a3b3bc68..66ee9916c83 100644
--- a/eval/CMakeLists.txt
+++ b/eval/CMakeLists.txt
@@ -32,6 +32,7 @@ vespa_define_module(
src/tests/eval/value_codec
src/tests/eval/value_type
src/tests/gp/ponder_nov2017
+ src/tests/instruction/generic_join
src/tests/instruction/generic_rename
src/tests/tensor/dense_add_dimension_optimizer
src/tests/tensor/dense_dimension_combiner
diff --git a/eval/src/tests/eval/simple_value/simple_value_test.cpp b/eval/src/tests/eval/simple_value/simple_value_test.cpp
index 6fa89989bb7..4827fa3be3c 100644
--- a/eval/src/tests/eval/simple_value/simple_value_test.cpp
+++ b/eval/src/tests/eval/simple_value/simple_value_test.cpp
@@ -2,8 +2,7 @@
#include <vespa/eval/eval/simple_value.h>
#include <vespa/eval/eval/value_codec.h>
-#include <vespa/eval/eval/tensor_plans.h>
-#include <vespa/eval/eval/tensor_instructions.h>
+#include <vespa/eval/instruction/generic_join.h>
#include <vespa/eval/eval/interpreted_function.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/vespalib/util/stringfmt.h>
@@ -11,6 +10,7 @@
using namespace vespalib;
using namespace vespalib::eval;
+using namespace vespalib::eval::instruction;
using namespace vespalib::eval::test;
using vespalib::make_string_short::fmt;
@@ -70,7 +70,7 @@ TensorSpec simple_value_new_join(const TensorSpec &a, const TensorSpec &b, join_
const auto &factory = SimpleValueBuilderFactory::get();
auto lhs = value_from_spec(a, factory);
auto rhs = value_from_spec(b, factory);
- auto my_op = tensor_instruction::make_join(lhs->type(), rhs->type(), function, factory, stash);
+ auto my_op = GenericJoin::make_instruction(lhs->type(), rhs->type(), function, factory, stash);
InterpretedFunction::EvalSingle single(my_op);
return spec_from_value(single.eval(std::vector<Value::CREF>({*lhs,*rhs})));
}
@@ -115,48 +115,6 @@ TEST(SimpleValueTest, simple_value_can_be_built_and_inspected) {
EXPECT_FALSE(view->next_result({&label}, subspace));
}
-TEST(SimpleValueTest, dense_join_plan_can_be_created) {
- auto lhs = ValueType::from_spec("tensor(a{},b[6],c[5],e[3],f[2],g{})");
- auto rhs = ValueType::from_spec("tensor(a{},b[6],c[5],d[4],h{})");
- auto plan = DenseJoinPlan(lhs, rhs);
- std::vector<size_t> expect_loop = {30,4,6};
- std::vector<size_t> expect_lhs_stride = {6,0,1};
- std::vector<size_t> expect_rhs_stride = {4,1,0};
- EXPECT_EQ(plan.lhs_size, 180);
- EXPECT_EQ(plan.rhs_size, 120);
- EXPECT_EQ(plan.out_size, 720);
- EXPECT_EQ(plan.loop_cnt, expect_loop);
- EXPECT_EQ(plan.lhs_stride, expect_lhs_stride);
- EXPECT_EQ(plan.rhs_stride, expect_rhs_stride);
-}
-
-TEST(SimpleValueTest, sparse_join_plan_can_be_created) {
- auto lhs = ValueType::from_spec("tensor(a{},b[6],c[5],e[3],f[2],g{})");
- auto rhs = ValueType::from_spec("tensor(b[6],c[5],d[4],g{},h{})");
- auto plan = SparseJoinPlan(lhs, rhs);
- using SRC = SparseJoinPlan::Source;
- std::vector<SRC> expect_sources = {SRC::LHS,SRC::BOTH,SRC::RHS};
- std::vector<size_t> expect_lhs_overlap = {1};
- std::vector<size_t> expect_rhs_overlap = {0};
- EXPECT_EQ(plan.sources, expect_sources);
- EXPECT_EQ(plan.lhs_overlap, expect_lhs_overlap);
- EXPECT_EQ(plan.rhs_overlap, expect_rhs_overlap);
-}
-
-TEST(SimpleValueTest, dense_join_plan_can_be_executed) {
- auto plan = DenseJoinPlan(ValueType::from_spec("tensor(a[2])"),
- ValueType::from_spec("tensor(b[3])"));
- std::vector<int> a({1, 2});
- std::vector<int> b({3, 4, 5});
- std::vector<int> c(6, 0);
- std::vector<int> expect = {3,4,5,6,8,10};
- ASSERT_EQ(plan.out_size, 6);
- int *dst = &c[0];
- auto cell_join = [&](size_t a_idx, size_t b_idx) { *dst++ = (a[a_idx] * b[b_idx]); };
- plan.execute(0, 0, cell_join);
- EXPECT_EQ(c, expect);
-}
-
TEST(SimpleValueTest, new_generic_join_works_for_simple_values) {
ASSERT_TRUE((join_layouts.size() % 2) == 0);
for (size_t i = 0; i < join_layouts.size(); i += 2) {
diff --git a/eval/src/tests/instruction/generic_join/CMakeLists.txt b/eval/src/tests/instruction/generic_join/CMakeLists.txt
new file mode 100644
index 00000000000..13fc6550d3c
--- /dev/null
+++ b/eval/src/tests/instruction/generic_join/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(eval_generic_join_test_app TEST
+ SOURCES
+ generic_join_test.cpp
+ DEPENDS
+ vespaeval
+ GTest::GTest
+)
+vespa_add_test(NAME eval_generic_join_test_app COMMAND eval_generic_join_test_app)
diff --git a/eval/src/tests/instruction/generic_join/generic_join_test.cpp b/eval/src/tests/instruction/generic_join/generic_join_test.cpp
new file mode 100644
index 00000000000..53df23d77be
--- /dev/null
+++ b/eval/src/tests/instruction/generic_join/generic_join_test.cpp
@@ -0,0 +1,119 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/eval/eval/simple_value.h>
+#include <vespa/eval/eval/value_codec.h>
+#include <vespa/eval/instruction/generic_join.h>
+#include <vespa/eval/eval/interpreted_function.h>
+#include <vespa/eval/eval/test/tensor_model.hpp>
+#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using namespace vespalib;
+using namespace vespalib::eval;
+using namespace vespalib::eval::instruction;
+using namespace vespalib::eval::test;
+
+using vespalib::make_string_short::fmt;
+
+std::vector<Layout> join_layouts = {
+ {}, {},
+ {x(5)}, {x(5)},
+ {x(5)}, {y(5)},
+ {x(5)}, {x(5),y(5)},
+ {y(3)}, {x(2),z(3)},
+ {x(3),y(5)}, {y(5),z(7)},
+ float_cells({x(3),y(5)}), {y(5),z(7)},
+ {x(3),y(5)}, float_cells({y(5),z(7)}),
+ float_cells({x(3),y(5)}), float_cells({y(5),z(7)}),
+ {x({"a","b","c"})}, {x({"a","b","c"})},
+ {x({"a","b","c"})}, {x({"a","b"})},
+ {x({"a","b","c"})}, {y({"foo","bar","baz"})},
+ {x({"a","b","c"})}, {x({"a","b","c"}),y({"foo","bar","baz"})},
+ {x({"a","b"}),y({"foo","bar","baz"})}, {x({"a","b","c"}),y({"foo","bar"})},
+ {x({"a","b"}),y({"foo","bar","baz"})}, {y({"foo","bar"}),z({"i","j","k","l"})},
+ float_cells({x({"a","b"}),y({"foo","bar","baz"})}), {y({"foo","bar"}),z({"i","j","k","l"})},
+ {x({"a","b"}),y({"foo","bar","baz"})}, float_cells({y({"foo","bar"}),z({"i","j","k","l"})}),
+ float_cells({x({"a","b"}),y({"foo","bar","baz"})}), float_cells({y({"foo","bar"}),z({"i","j","k","l"})}),
+ {x(3),y({"foo", "bar"})}, {y({"foo", "bar"}),z(7)},
+ {x({"a","b","c"}),y(5)}, {y(5),z({"i","j","k","l"})},
+ float_cells({x({"a","b","c"}),y(5)}), {y(5),z({"i","j","k","l"})},
+ {x({"a","b","c"}),y(5)}, float_cells({y(5),z({"i","j","k","l"})}),
+ float_cells({x({"a","b","c"}),y(5)}), float_cells({y(5),z({"i","j","k","l"})})
+};
+
+TensorSpec simple_tensor_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
+ Stash stash;
+ const auto &engine = SimpleTensorEngine::ref();
+ auto lhs = engine.from_spec(a);
+ auto rhs = engine.from_spec(b);
+ const auto &result = engine.join(*lhs, *rhs, function, stash);
+ return engine.to_spec(result);
+}
+
+TensorSpec perform_generic_join(const TensorSpec &a, const TensorSpec &b, join_fun_t function) {
+ Stash stash;
+ const auto &factory = SimpleValueBuilderFactory::get();
+ auto lhs = value_from_spec(a, factory);
+ auto rhs = value_from_spec(b, factory);
+ auto my_op = GenericJoin::make_instruction(lhs->type(), rhs->type(), function, factory, stash);
+ InterpretedFunction::EvalSingle single(my_op);
+ return spec_from_value(single.eval(std::vector<Value::CREF>({*lhs,*rhs})));
+}
+
+TEST(GenericJoinTest, dense_join_plan_can_be_created) {
+ auto lhs = ValueType::from_spec("tensor(a{},b[6],c[5],e[3],f[2],g{})");
+ auto rhs = ValueType::from_spec("tensor(a{},b[6],c[5],d[4],h{})");
+ auto plan = DenseJoinPlan(lhs, rhs);
+ std::vector<size_t> expect_loop = {30,4,6};
+ std::vector<size_t> expect_lhs_stride = {6,0,1};
+ std::vector<size_t> expect_rhs_stride = {4,1,0};
+ EXPECT_EQ(plan.lhs_size, 180);
+ EXPECT_EQ(plan.rhs_size, 120);
+ EXPECT_EQ(plan.out_size, 720);
+ EXPECT_EQ(plan.loop_cnt, expect_loop);
+ EXPECT_EQ(plan.lhs_stride, expect_lhs_stride);
+ EXPECT_EQ(plan.rhs_stride, expect_rhs_stride);
+}
+
+TEST(GenericJoinTest, sparse_join_plan_can_be_created) {
+ auto lhs = ValueType::from_spec("tensor(a{},b[6],c[5],e[3],f[2],g{})");
+ auto rhs = ValueType::from_spec("tensor(b[6],c[5],d[4],g{},h{})");
+ auto plan = SparseJoinPlan(lhs, rhs);
+ using SRC = SparseJoinPlan::Source;
+ std::vector<SRC> expect_sources = {SRC::LHS,SRC::BOTH,SRC::RHS};
+ std::vector<size_t> expect_lhs_overlap = {1};
+ std::vector<size_t> expect_rhs_overlap = {0};
+ EXPECT_EQ(plan.sources, expect_sources);
+ EXPECT_EQ(plan.lhs_overlap, expect_lhs_overlap);
+ EXPECT_EQ(plan.rhs_overlap, expect_rhs_overlap);
+}
+
+TEST(GenericJoinTest, dense_join_plan_can_be_executed) {
+ auto plan = DenseJoinPlan(ValueType::from_spec("tensor(a[2])"),
+ ValueType::from_spec("tensor(b[3])"));
+ std::vector<int> a({1, 2});
+ std::vector<int> b({3, 4, 5});
+ std::vector<int> c(6, 0);
+ std::vector<int> expect = {3,4,5,6,8,10};
+ ASSERT_EQ(plan.out_size, 6);
+ int *dst = &c[0];
+ auto cell_join = [&](size_t a_idx, size_t b_idx) { *dst++ = (a[a_idx] * b[b_idx]); };
+ plan.execute(0, 0, cell_join);
+ EXPECT_EQ(c, expect);
+}
+
+TEST(GenericJoinTest, generic_join_works_for_simple_values) {
+ ASSERT_TRUE((join_layouts.size() % 2) == 0);
+ for (size_t i = 0; i < join_layouts.size(); i += 2) {
+ TensorSpec lhs = spec(join_layouts[i], Div16(N()));
+ TensorSpec rhs = spec(join_layouts[i + 1], Div16(N()));
+ for (auto fun: {operation::Add::f, operation::Sub::f, operation::Mul::f, operation::Div::f}) {
+ SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
+ auto expect = simple_tensor_join(lhs, rhs, fun);
+ auto actual = perform_generic_join(lhs, rhs, fun);
+ EXPECT_EQ(actual, expect);
+ }
+ }
+}
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp b/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
index 31e82a01070..1139d35d847 100644
--- a/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
+++ b/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
@@ -10,6 +10,7 @@
using namespace vespalib;
using namespace vespalib::eval;
+using namespace vespalib::eval::instruction;
using namespace vespalib::eval::test;
using vespalib::make_string_short::fmt;
@@ -50,7 +51,7 @@ TEST(GenericRenameTest, dense_rename_plan_can_be_created_and_executed) {
std::vector<vespalib::string> from({"a", "c", "e"});
std::vector<vespalib::string> to({"f", "a", "b"});
ValueType renamed = lhs.rename(from, to);
- auto plan = instruction::DenseRenamePlan(lhs, renamed, from, to);
+ auto plan = DenseRenamePlan(lhs, renamed, from, to);
std::vector<size_t> expect_loop = {15,2,7};
std::vector<size_t> expect_stride = {7,105,1};
EXPECT_EQ(plan.subspace_size, 210);
@@ -80,7 +81,7 @@ TEST(GenericRenameTest, sparse_rename_plan_can_be_created) {
std::vector<vespalib::string> from({"a", "c", "e"});
std::vector<vespalib::string> to({"f", "a", "b"});
ValueType renamed = lhs.rename(from, to);
- auto plan = instruction::SparseRenamePlan(lhs, renamed, from, to);
+ auto plan = SparseRenamePlan(lhs, renamed, from, to);
EXPECT_EQ(plan.mapped_dims, 4);
std::vector<size_t> expect = {2,0,1,3};
EXPECT_EQ(plan.output_dimensions, expect);
@@ -99,7 +100,7 @@ TensorSpec perform_generic_rename(const TensorSpec &a, const ValueType &res_type
{
Stash stash;
auto lhs = value_from_spec(a, factory);
- auto my_op = instruction::GenericRename::make_instruction(lhs->type(), res_type, ft.from, ft.to, factory, stash);
+ auto my_op = GenericRename::make_instruction(lhs->type(), res_type, ft.from, ft.to, factory, stash);
InterpretedFunction::EvalSingle single(my_op);
return spec_from_value(single.eval(std::vector<Value::CREF>({*lhs})));
}
diff --git a/eval/src/vespa/eval/eval/CMakeLists.txt b/eval/src/vespa/eval/eval/CMakeLists.txt
index 53ee6ed87c0..84cebe8cfd0 100644
--- a/eval/src/vespa/eval/eval/CMakeLists.txt
+++ b/eval/src/vespa/eval/eval/CMakeLists.txt
@@ -25,9 +25,7 @@ vespa_add_library(eval_eval OBJECT
tensor.cpp
tensor_engine.cpp
tensor_function.cpp
- tensor_instructions.cpp
tensor_nodes.cpp
- tensor_plans.cpp
tensor_spec.cpp
value.cpp
value_codec.cpp
diff --git a/eval/src/vespa/eval/eval/tensor_instructions.h b/eval/src/vespa/eval/eval/tensor_instructions.h
deleted file mode 100644
index f5c5e88d07c..00000000000
--- a/eval/src/vespa/eval/eval/tensor_instructions.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include "interpreted_function.h"
-
-namespace vespalib {
-
-class Stash;
-
-namespace eval {
-
-struct JoinPlan;
-
-namespace tensor_instruction {
-
-using join_fun_t = double (*)(double, double);
-
-InterpretedFunction::Instruction make_join(const ValueType &lhs_type, const ValueType &rhs_type, join_fun_t function,
- const ValueBuilderFactory &factory, Stash &stash);
-
-}
-}
-}
diff --git a/eval/src/vespa/eval/eval/tensor_plans.cpp b/eval/src/vespa/eval/eval/tensor_plans.cpp
deleted file mode 100644
index 203ca72c92a..00000000000
--- a/eval/src/vespa/eval/eval/tensor_plans.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "tensor_plans.h"
-#include <vespa/vespalib/util/visit_ranges.h>
-#include <vespa/vespalib/util/overload.h>
-#include <cassert>
-
-namespace vespalib::eval {
-
-//-----------------------------------------------------------------------------
-
-DenseJoinPlan::DenseJoinPlan(const ValueType &lhs_type, const ValueType &rhs_type)
- : lhs_size(1), rhs_size(1), out_size(1), loop_cnt(), lhs_stride(), rhs_stride()
-{
- enum class Case { NONE, LHS, RHS, BOTH };
- Case prev_case = Case::NONE;
- auto update_plan = [&](Case my_case, size_t my_size, size_t in_lhs, size_t in_rhs) {
- if (my_case == prev_case) {
- assert(!loop_cnt.empty());
- loop_cnt.back() *= my_size;
- } else {
- loop_cnt.push_back(my_size);
- lhs_stride.push_back(in_lhs);
- rhs_stride.push_back(in_rhs);
- prev_case = my_case;
- }
- };
- auto visitor = overload
- {
- [&](visit_ranges_first, const auto &a) { update_plan(Case::LHS, a.size, 1, 0); },
- [&](visit_ranges_second, const auto &b) { update_plan(Case::RHS, b.size, 0, 1); },
- [&](visit_ranges_both, const auto &a, const auto &) { update_plan(Case::BOTH, a.size, 1, 1); }
- };
- auto lhs_dims = lhs_type.nontrivial_indexed_dimensions();
- auto rhs_dims = rhs_type.nontrivial_indexed_dimensions();
- visit_ranges(visitor, lhs_dims.begin(), lhs_dims.end(), rhs_dims.begin(), rhs_dims.end(),
- [](const auto &a, const auto &b){ return (a.name < b.name); });
- for (size_t i = loop_cnt.size(); i-- > 0; ) {
- out_size *= loop_cnt[i];
- if (lhs_stride[i] != 0) {
- lhs_stride[i] = lhs_size;
- lhs_size *= loop_cnt[i];
- }
- if (rhs_stride[i] != 0) {
- rhs_stride[i] = rhs_size;
- rhs_size *= loop_cnt[i];
- }
- }
-}
-
-DenseJoinPlan::~DenseJoinPlan() = default;
-
-//-----------------------------------------------------------------------------
-
-SparseJoinPlan::SparseJoinPlan(const ValueType &lhs_type, const ValueType &rhs_type)
- : sources(), lhs_overlap(), rhs_overlap()
-{
- size_t lhs_idx = 0;
- size_t rhs_idx = 0;
- auto visitor = overload
- {
- [&](visit_ranges_first, const auto &) {
- sources.push_back(Source::LHS);
- ++lhs_idx;
- },
- [&](visit_ranges_second, const auto &) {
- sources.push_back(Source::RHS);
- ++rhs_idx;
- },
- [&](visit_ranges_both, const auto &, const auto &) {
- sources.push_back(Source::BOTH);
- lhs_overlap.push_back(lhs_idx++);
- rhs_overlap.push_back(rhs_idx++);
- }
- };
- auto lhs_dims = lhs_type.mapped_dimensions();
- auto rhs_dims = rhs_type.mapped_dimensions();
- visit_ranges(visitor, lhs_dims.begin(), lhs_dims.end(), rhs_dims.begin(), rhs_dims.end(),
- [](const auto &a, const auto &b){ return (a.name < b.name); });
-}
-
-SparseJoinPlan::~SparseJoinPlan() = default;
-
-//-----------------------------------------------------------------------------
-
-}
diff --git a/eval/src/vespa/eval/instruction/CMakeLists.txt b/eval/src/vespa/eval/instruction/CMakeLists.txt
index f5a7de96f0b..e5aae50750d 100644
--- a/eval/src/vespa/eval/instruction/CMakeLists.txt
+++ b/eval/src/vespa/eval/instruction/CMakeLists.txt
@@ -2,5 +2,6 @@
vespa_add_library(eval_instruction OBJECT
SOURCES
+ generic_join
generic_rename
)
diff --git a/eval/src/vespa/eval/eval/tensor_instructions.cpp b/eval/src/vespa/eval/instruction/generic_join.cpp
index d839bfdad50..8a1a199effa 100644
--- a/eval/src/vespa/eval/eval/tensor_instructions.cpp
+++ b/eval/src/vespa/eval/instruction/generic_join.cpp
@@ -1,18 +1,18 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include "tensor_instructions.h"
-#include "tensor_plans.h"
-#include "inline_operation.h"
+#include "generic_join.h"
+#include <vespa/eval/eval/inline_operation.h>
+#include <vespa/vespalib/util/overload.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/typify.h>
+#include <vespa/vespalib/util/visit_ranges.h>
+#include <cassert>
-namespace vespalib::eval::tensor_instruction {
+namespace vespalib::eval::instruction {
using State = InterpretedFunction::State;
using Instruction = InterpretedFunction::Instruction;
-//-----------------------------------------------------------------------------
-
namespace {
//-----------------------------------------------------------------------------
@@ -95,8 +95,13 @@ struct SparseJoinState {
};
SparseJoinState::~SparseJoinState() = default;
+/*
+template <typename LCT, typename RCT, typename OCT, typename Fun>
+void generic_join()
+*/
+
template <typename LCT, typename RCT, typename OCT, typename Fun>
-void my_generic_join(State &state, uint64_t param_in) {
+void my_generic_join_op(State &state, uint64_t param_in) {
const auto &param = unwrap_param<JoinParam>(param_in);
Fun fun(param.function);
const Value &lhs = state.peek(1);
@@ -121,9 +126,9 @@ void my_generic_join(State &state, uint64_t param_in) {
state.pop_pop_push(result_ref);
};
-struct SelectGenericJoin {
+struct SelectGenericJoinOp {
template <typename LCT, typename RCT, typename OCT, typename Fun> static auto invoke() {
- return my_generic_join<LCT,RCT,OCT,Fun>;
+ return my_generic_join_op<LCT,RCT,OCT,Fun>;
}
};
@@ -133,16 +138,95 @@ struct SelectGenericJoin {
//-----------------------------------------------------------------------------
-using JoinTypify = TypifyValue<TypifyCellType,operation::TypifyOp2>;
+DenseJoinPlan::DenseJoinPlan(const ValueType &lhs_type, const ValueType &rhs_type)
+ : lhs_size(1), rhs_size(1), out_size(1), loop_cnt(), lhs_stride(), rhs_stride()
+{
+ enum class Case { NONE, LHS, RHS, BOTH };
+ Case prev_case = Case::NONE;
+ auto update_plan = [&](Case my_case, size_t my_size, size_t in_lhs, size_t in_rhs) {
+ if (my_case == prev_case) {
+ assert(!loop_cnt.empty());
+ loop_cnt.back() *= my_size;
+ } else {
+ loop_cnt.push_back(my_size);
+ lhs_stride.push_back(in_lhs);
+ rhs_stride.push_back(in_rhs);
+ prev_case = my_case;
+ }
+ };
+ auto visitor = overload
+ {
+ [&](visit_ranges_first, const auto &a) { update_plan(Case::LHS, a.size, 1, 0); },
+ [&](visit_ranges_second, const auto &b) { update_plan(Case::RHS, b.size, 0, 1); },
+ [&](visit_ranges_both, const auto &a, const auto &) { update_plan(Case::BOTH, a.size, 1, 1); }
+ };
+ auto lhs_dims = lhs_type.nontrivial_indexed_dimensions();
+ auto rhs_dims = rhs_type.nontrivial_indexed_dimensions();
+ visit_ranges(visitor, lhs_dims.begin(), lhs_dims.end(), rhs_dims.begin(), rhs_dims.end(),
+ [](const auto &a, const auto &b){ return (a.name < b.name); });
+ for (size_t i = loop_cnt.size(); i-- > 0; ) {
+ out_size *= loop_cnt[i];
+ if (lhs_stride[i] != 0) {
+ lhs_stride[i] = lhs_size;
+ lhs_size *= loop_cnt[i];
+ }
+ if (rhs_stride[i] != 0) {
+ rhs_stride[i] = rhs_size;
+ rhs_size *= loop_cnt[i];
+ }
+ }
+}
+
+DenseJoinPlan::~DenseJoinPlan() = default;
+
+//-----------------------------------------------------------------------------
-Instruction make_join(const ValueType &lhs_type, const ValueType &rhs_type, join_fun_t function,
- const ValueBuilderFactory &factory, Stash &stash)
+SparseJoinPlan::SparseJoinPlan(const ValueType &lhs_type, const ValueType &rhs_type)
+ : sources(), lhs_overlap(), rhs_overlap()
{
- auto &param = stash.create<JoinParam>(lhs_type, rhs_type, function, factory);
- auto fun = typify_invoke<4,JoinTypify,SelectGenericJoin>(lhs_type.cell_type(), rhs_type.cell_type(), param.res_type.cell_type(), function);
- return Instruction(fun, wrap_param<JoinParam>(param));
+ size_t lhs_idx = 0;
+ size_t rhs_idx = 0;
+ auto visitor = overload
+ {
+ [&](visit_ranges_first, const auto &) {
+ sources.push_back(Source::LHS);
+ ++lhs_idx;
+ },
+ [&](visit_ranges_second, const auto &) {
+ sources.push_back(Source::RHS);
+ ++rhs_idx;
+ },
+ [&](visit_ranges_both, const auto &, const auto &) {
+ sources.push_back(Source::BOTH);
+ lhs_overlap.push_back(lhs_idx++);
+ rhs_overlap.push_back(rhs_idx++);
+ }
+ };
+ auto lhs_dims = lhs_type.mapped_dimensions();
+ auto rhs_dims = rhs_type.mapped_dimensions();
+ visit_ranges(visitor, lhs_dims.begin(), lhs_dims.end(), rhs_dims.begin(), rhs_dims.end(),
+ [](const auto &a, const auto &b){ return (a.name < b.name); });
+}
+
+SparseJoinPlan::~SparseJoinPlan() = default;
+
+//-----------------------------------------------------------------------------
+
}
//-----------------------------------------------------------------------------
+namespace vespalib::eval::instruction {
+
+using JoinTypify = TypifyValue<TypifyCellType,operation::TypifyOp2>;
+
+Instruction
+GenericJoin::make_instruction(const ValueType &lhs_type, const ValueType &rhs_type, join_fun_t function,
+ const ValueBuilderFactory &factory, Stash &stash)
+{
+ auto &param = stash.create<JoinParam>(lhs_type, rhs_type, function, factory);
+ auto fun = typify_invoke<4,JoinTypify,SelectGenericJoinOp>(lhs_type.cell_type(), rhs_type.cell_type(), param.res_type.cell_type(), function);
+ return Instruction(fun, wrap_param<JoinParam>(param));
}
+
+} // namespace
diff --git a/eval/src/vespa/eval/eval/tensor_plans.h b/eval/src/vespa/eval/instruction/generic_join.h
index 9a924a8ba48..81e56494897 100644
--- a/eval/src/vespa/eval/eval/tensor_plans.h
+++ b/eval/src/vespa/eval/instruction/generic_join.h
@@ -2,13 +2,23 @@
#pragma once
-#include "value_type.h"
-#include <vespa/vespalib/stllike/string.h>
-#include <vector>
+#include <vespa/eval/eval/value_type.h>
+#include <vespa/eval/eval/interpreted_function.h>
-namespace vespalib::eval {
+namespace vespalib { class Stash; }
+namespace vespalib::eval { class ValueBuilderFactory; }
-class ValueBuilderFactory;
+namespace vespalib::eval::instruction {
+
+using join_fun_t = double (*)(double, double);
+
+//-----------------------------------------------------------------------------
+
+struct GenericJoin {
+ static InterpretedFunction::Instruction
+ make_instruction(const ValueType &lhs_type, const ValueType &rhs_type, join_fun_t function,
+ const ValueBuilderFactory &factory, Stash &stash);
+};
//-----------------------------------------------------------------------------
@@ -74,4 +84,4 @@ struct SparseJoinPlan {
//-----------------------------------------------------------------------------
-}
+} // namespace