Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions tuple/include/array_tuple_intersection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ class array_tuple_intersection: public tuple_intersection<Array, Policy, Allocat
*/
explicit array_tuple_intersection(uint64_t seed = DEFAULT_SEED, const Policy& policy = Policy(), const Allocator& allocator = Allocator());

/**
* Updates the intersection with a given sketch.
* The sketch must have the same number of values as the intersection policy.
* @param sketch to intersect with
* @throw std::invalid_argument if the number of values does not match
*/
template<typename FwdSketch>
void update(FwdSketch&& sketch);

/**
* Produces a copy of the current state of the intersection.
* If update() was not called, the state is the infinite "universe",
Expand Down
14 changes: 14 additions & 0 deletions tuple/include/array_tuple_intersection_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,26 @@
* under the License.
*/

#include <stdexcept>
#include <string>

namespace datasketches {

template<typename Array, typename Policy, typename Allocator>
array_tuple_intersection<Array, Policy, Allocator>::array_tuple_intersection(uint64_t seed, const Policy& policy, const Allocator& allocator):
Base(seed, policy, allocator) {}

template<typename Array, typename Policy, typename Allocator>
template<typename FwdSketch>
void array_tuple_intersection<Array, Policy, Allocator>::update(FwdSketch&& sketch) {
const uint8_t num_values = this->state_.get_policy().get_external_policy().get_num_values();
if (sketch.get_num_values() != num_values) {
throw std::invalid_argument("number of values mismatch: intersection has " + std::to_string(num_values)
+ ", sketch has " + std::to_string(sketch.get_num_values()));
}
Base::update(std::forward<FwdSketch>(sketch));
}

template<typename Array, typename Policy, typename Allocator>
auto array_tuple_intersection<Array, Policy, Allocator>::get_result(bool ordered) const -> CompactSketch {
return CompactSketch(this->state_.get_policy().get_external_policy().get_num_values(), Base::get_result(ordered));
Expand Down
9 changes: 9 additions & 0 deletions tuple/include/array_tuple_union.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ class array_tuple_union: public tuple_union<Array, Policy, Allocator> {

class builder;

/**
* Update the union with a given sketch.
* The sketch must have the same number of values as the union policy.
* @param sketch to update the union with
* @throw std::invalid_argument if the number of values does not match
*/
template<typename FwdSketch>
void update(FwdSketch&& sketch);

CompactSketch get_result(bool ordered = true) const;

private:
Expand Down
14 changes: 14 additions & 0 deletions tuple/include/array_tuple_union_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,27 @@
* under the License.
*/

#include <stdexcept>
#include <string>

namespace datasketches {

template<typename Array, typename Policy, typename Allocator>
array_tuple_union<Array, Policy, Allocator>::array_tuple_union(uint8_t lg_cur_size, uint8_t lg_nom_size, resize_factor rf, float p, uint64_t theta, uint64_t seed, const Policy& policy, const Allocator& allocator):
Base(lg_cur_size, lg_nom_size, rf, p, theta, seed, policy, allocator)
{}

template<typename Array, typename Policy, typename Allocator>
template<typename FwdSketch>
void array_tuple_union<Array, Policy, Allocator>::update(FwdSketch&& sketch) {
const uint8_t num_values = this->state_.get_policy().get_external_policy().get_num_values();
if (sketch.get_num_values() != num_values) {
throw std::invalid_argument("number of values mismatch: union has " + std::to_string(num_values)
+ ", sketch has " + std::to_string(sketch.get_num_values()));
}
Base::update(std::forward<FwdSketch>(sketch));
}

template<typename Array, typename Policy, typename Allocator>
auto array_tuple_union<Array, Policy, Allocator>::get_result(bool ordered) const -> CompactSketch {
return CompactSketch(this->state_.get_policy().get_external_policy().get_num_values(), Base::get_result(ordered));
Expand Down
47 changes: 47 additions & 0 deletions tuple/test/array_of_doubles_sketch_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,53 @@ TEST_CASE("aod intersection: half overlap", "[tuple_sketch]") {
REQUIRE(result.get_estimate() == Approx(500).margin(0.01));
}

TEST_CASE("aod union: number of values", "[tuple_sketch]") {
auto sketch1 = update_array_of_doubles_sketch::builder(1).build();
sketch1.update(1, std::vector<double>{1});
auto sketch3 = update_array_of_doubles_sketch::builder(3).build();
sketch3.update(1, std::vector<double>{1, 2, 3});
sketch3.update(2, std::vector<double>{4, 5, 6});

// matching number of values: entries for the same key are summed
auto u = array_of_doubles_union::builder(3).build();
u.update(sketch3);
u.update(sketch3.compact());
auto result = u.get_result();
REQUIRE(result.get_num_values() == 3);
REQUIRE(result.get_num_retained() == 2);
for (const auto& entry: result) {
REQUIRE(entry.second.size() == 3);
}

// mismatch is rejected whether or not keys overlap, and for update and compact sketches
REQUIRE_THROWS_AS(u.update(sketch1), std::invalid_argument);
REQUIRE_THROWS_AS(u.update(sketch1.compact()), std::invalid_argument);
auto u1 = array_of_doubles_union::builder(1).build();
REQUIRE_THROWS_AS(u1.update(sketch3), std::invalid_argument);
auto empty3 = update_array_of_doubles_sketch::builder(3).build();
REQUIRE_THROWS_AS(u1.update(empty3), std::invalid_argument);

// a rejected update leaves the union usable
u1.update(sketch1);
REQUIRE(u1.get_result().get_num_retained() == 1);
}

TEST_CASE("aod intersection: number of values", "[tuple_sketch]") {
auto sketch1 = update_array_of_doubles_sketch::builder(1).build();
sketch1.update(1, std::vector<double>{1});
auto sketch3 = update_array_of_doubles_sketch::builder(3).build();
sketch3.update(1, std::vector<double>{1, 2, 3});

array_of_doubles_intersection<default_array_of_doubles_union_policy> intersection(DEFAULT_SEED, 3);
REQUIRE_THROWS_AS(intersection.update(sketch1), std::invalid_argument);
intersection.update(sketch3);
REQUIRE_THROWS_AS(intersection.update(sketch1.compact()), std::invalid_argument);
intersection.update(sketch3.compact());
auto result = intersection.get_result();
REQUIRE(result.get_num_values() == 3);
REQUIRE(result.get_num_retained() == 1);
}

TEST_CASE("aod a-not-b: half overlap", "[tuple_sketch]") {
double a[1] = {1};

Expand Down
Loading