summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2021-03-12 09:09:40 +0000
committerHåvard Pettersen <havardpe@oath.com>2021-03-12 11:19:34 +0000
commitbcbf0018e423910c10217a4ce71cc07053f5b6e4 (patch)
tree2085765f9825199bbe62c2668d677cdf4aa63a4b
parentcdf52990f001826004b52b39acf99647c7f7b0f7 (diff)
add new way to make a GenSpec based on a textual description
-rw-r--r--eval/src/tests/eval/gen_spec/gen_spec_test.cpp22
-rw-r--r--eval/src/vespa/eval/eval/test/gen_spec.cpp62
-rw-r--r--eval/src/vespa/eval/eval/test/gen_spec.h21
3 files changed, 104 insertions, 1 deletions
diff --git a/eval/src/tests/eval/gen_spec/gen_spec_test.cpp b/eval/src/tests/eval/gen_spec/gen_spec_test.cpp
index 9d8eb419a67..30ef42d7ebb 100644
--- a/eval/src/tests/eval/gen_spec/gen_spec_test.cpp
+++ b/eval/src/tests/eval/gen_spec/gen_spec_test.cpp
@@ -32,11 +32,13 @@ TEST(DimSpecTest, mapped_dimension) {
TEST(DimSpecTest, simple_dictionary_creation) {
auto dict = DimSpec::make_dict(5, 1, "");
std::vector<vespalib::string> expect = {"0", "1", "2", "3", "4"};
+ EXPECT_EQ(dict, expect);
}
TEST(DimSpecTest, advanced_dictionary_creation) {
auto dict = DimSpec::make_dict(5, 3, "str_");
std::vector<vespalib::string> expect = {"str_0", "str_3", "str_6", "str_9", "str_12"};
+ EXPECT_EQ(dict, expect);
}
//-----------------------------------------------------------------------------
@@ -234,4 +236,24 @@ TEST(GenSpecTest, gen_spec_can_be_implicitly_converted_to_tensor_spec) {
//-----------------------------------------------------------------------------
+TEST(GenSpecFromDescTest, dim_spec_and_gen_spec_can_be_created_from_desc) {
+ // 'a2b3#7c5#'
+ auto expect = GenSpec().idx("a", 2).map("b", 3, 7).map("c", 5).gen();
+ auto dim_desc = GenSpec().desc("a2").desc("b3#7").desc("c5#").gen();
+ auto gen_desc = GenSpec::from_desc("a2b3#7c5#").gen();
+ EXPECT_EQ(dim_desc, expect);
+ EXPECT_EQ(gen_desc, expect);
+}
+
+TEST(GenSpecFromDescTest, multi_character_sizes_work) {
+ // 'a13b1'
+ auto expect = GenSpec().idx("a", 13).idx("b", 1).gen();
+ auto dim_desc = GenSpec().desc("a13").desc("b1").gen();
+ auto gen_desc = GenSpec::from_desc("a13b1").gen();
+ EXPECT_EQ(dim_desc, expect);
+ EXPECT_EQ(gen_desc, expect);
+}
+
+//-----------------------------------------------------------------------------
+
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/vespa/eval/eval/test/gen_spec.cpp b/eval/src/vespa/eval/eval/test/gen_spec.cpp
index a308cbeff46..87e49c376d1 100644
--- a/eval/src/vespa/eval/eval/test/gen_spec.cpp
+++ b/eval/src/vespa/eval/eval/test/gen_spec.cpp
@@ -53,6 +53,68 @@ DimSpec::make_dict(size_t size, size_t stride, const vespalib::string &prefix)
return dict;
}
+// 'a2' -> DimSpec("a", 2);
+// 'b2#' -> DimSpec("b", make_dict(2, 1, ""));
+// 'c2#3' -> DimSpec("c", make_dict(2, 3, ""));
+DimSpec
+DimSpec::from_desc(const vespalib::string &desc)
+{
+ size_t idx = 0;
+ vespalib::string name;
+ auto is_num = [](char c) { return ((c >= '0') && (c <= '9')); };
+ auto as_num = [](char c) { return size_t(c - '0'); };
+ auto is_map_tag = [](char c) { return (c == '#'); };
+ auto is_dim_name = [](char c) { return ((c >= 'a') && (c <= 'z')); };
+ auto extract_number = [&]() {
+ assert(idx < desc.size());
+ assert(is_num(desc[idx]));
+ size_t num = as_num(desc[idx++]);
+ assert(num != 0); // catch leading zeroes/zero size
+ while ((idx < desc.size()) && is_num(desc[idx])) {
+ num = (num * 10) + as_num(desc[idx++]);
+ }
+ return num;
+ };
+ assert(!desc.empty());
+ assert(is_dim_name(desc[idx]));
+ name.push_back(desc[idx++]);
+ size_t size = extract_number();
+ if (idx < desc.size()) {
+ // mapped
+ assert(is_map_tag(desc[idx++]));
+ size_t stride = 1;
+ if (idx < desc.size()) {
+ stride = extract_number();
+ assert(idx == desc.size());
+ }
+ return {name, make_dict(size, stride, "")};
+ } else {
+ // indexed
+ return {name, size};
+ }
+}
+
+// 'a2b12c5' -> GenSpec().idx("a", 2).idx("b", 12).idx("c", 5);
+// 'a2#b3#2c5#' -> GenSpec().map("a", 2).map("b", 3, 2).map("c", 5);
+GenSpec
+GenSpec::from_desc(const vespalib::string &desc)
+{
+ size_t idx = 0;
+ vespalib::string dim_desc;
+ std::vector<DimSpec> dim_list;
+ auto is_dim_name = [](char c) { return ((c >= 'a') && (c <= 'z')); };
+ while (idx < desc.size()) {
+ dim_desc.clear();
+ assert(is_dim_name(desc[idx]));
+ dim_desc.push_back(desc[idx++]);
+ while ((idx < desc.size()) && !is_dim_name(desc[idx])) {
+ dim_desc.push_back(desc[idx++]);
+ }
+ dim_list.push_back(DimSpec::from_desc(dim_desc));
+ }
+ return {std::move(dim_list)};
+}
+
GenSpec::GenSpec(GenSpec &&other) = default;
GenSpec::GenSpec(const GenSpec &other) = default;
GenSpec &GenSpec::operator=(GenSpec &&other) = default;
diff --git a/eval/src/vespa/eval/eval/test/gen_spec.h b/eval/src/vespa/eval/eval/test/gen_spec.h
index bbc1663a11f..6943ba6c98a 100644
--- a/eval/src/vespa/eval/eval/test/gen_spec.h
+++ b/eval/src/vespa/eval/eval/test/gen_spec.h
@@ -76,6 +76,14 @@ public:
assert(idx < size());
return _size ? TensorSpec::Label{idx} : TensorSpec::Label{_dict[idx]};
}
+
+ // Make a DimSpec object from a textual description
+ // (first character is used as dimension name)
+ //
+ // 'a2' -> DimSpec("a", 2);
+ // 'b2#' -> DimSpec("b", make_dict(2, 1, ""));
+ // 'c2#3' -> DimSpec("c", make_dict(2, 3, ""));
+ static DimSpec from_desc(const vespalib::string &desc);
};
/**
@@ -95,7 +103,14 @@ private:
public:
GenSpec() : _dims(), _cells(CellType::DOUBLE), _seq(N()) {}
GenSpec(double bias) : _dims(), _cells(CellType::DOUBLE), _seq(N(bias)) {}
- GenSpec(const std::vector<DimSpec> &dims_in) : _dims(dims_in), _cells(CellType::DOUBLE), _seq(N()) {}
+ GenSpec(std::vector<DimSpec> dims_in) : _dims(std::move(dims_in)), _cells(CellType::DOUBLE), _seq(N()) {}
+
+ // Make a GenSpec object from a textual description
+ // (dimension names must be single characters a-z)
+ //
+ // 'a2b12c5' -> GenSpec().idx("a", 2).idx("b", 12).idx("c", 5);
+ // 'a2#b3#2c5#' -> GenSpec().map("a", 2).map("b", 3, 2).map("c", 5);
+ static GenSpec from_desc(const vespalib::string &desc);
GenSpec(GenSpec &&other);
GenSpec(const GenSpec &other);
@@ -118,6 +133,10 @@ public:
_dims.emplace_back(name, std::move(dict));
return *this;
}
+ GenSpec &desc(const vespalib::string &dim_desc) {
+ _dims.push_back(DimSpec::from_desc(dim_desc));
+ return *this;
+ }
GenSpec &cells(CellType cell_type) {
_cells = cell_type;
return *this;