libdatasketches_sys 0.1.3

Low-level bindings for Apache DataSketches C++ library
Documentation
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <ebpps_sample.hpp>

#include <catch2/catch.hpp>

#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <cmath>
#include <random>
#include <stdexcept>

namespace datasketches {

static constexpr double EPS = 1e-15;

TEST_CASE("ebpps sample: basic initialization", "[ebpps_sketch]") {
  ebpps_sample<int> sample = ebpps_sample<int>(0);
  REQUIRE(sample.get_c() == 0.0);
  REQUIRE(sample.get_num_retained_items() == 0);
  REQUIRE(sample.get_sample().size() == 0);
}

TEST_CASE("ebpps sample: pre-initialized", "[ebpps_sketch]") {
  double theta = 1.0;
  ebpps_sample<int> sample(1);
  sample.replace_content(-1, theta);
  REQUIRE(sample.get_c() == theta);
  REQUIRE(sample.get_num_retained_items() == 1);
  REQUIRE(sample.get_sample().size() == 1);
  REQUIRE(sample.has_partial_item() == false);
  
  theta = 1e-300;
  sample.replace_content(-1, theta);
  REQUIRE(sample.get_c() == theta);
  REQUIRE(sample.get_num_retained_items() == 1);
  REQUIRE(sample.get_sample().size() == 0); // assuming the random number is > 1e-300
  REQUIRE(sample.has_partial_item());
}

TEST_CASE("ebpps sample: downsampling", "[ebpps_sketch]") {
  ebpps_sample<char> sample(1);
  sample.replace_content('a', 1.0);

  sample.downsample(2.0); // no-op
  REQUIRE(sample.get_c() == 1.0);
  REQUIRE(sample.get_num_retained_items() == 1);
  REQUIRE(sample.has_partial_item() == false);

  // downsample and result in an empty sample
  random_utils::override_seed(12);
  std::vector<char> items = {'a', 'b'};
  optional<char> opt; // empty
  sample = ebpps_sample<char>(std::move(items), std::move(opt), 1.8);
  sample.downsample(0.5);
  REQUIRE(sample.get_c() == 0.9);
  REQUIRE(sample.get_num_retained_items() == 0);
  REQUIRE(sample.has_partial_item() == false);

  // downsample and result in a sample with a partial item
  items = {'a', 'b'};
  opt.reset();
  sample = ebpps_sample<char>(std::move(items), std::move(opt), 1.5);
  sample.downsample(0.5);
  REQUIRE(sample.get_c() == 0.75);
  REQUIRE(sample.get_num_retained_items() == 1);
  REQUIRE(sample.has_partial_item() == true);
  for (char c : sample) {
    REQUIRE((c == 'a' || c == 'b'));
  }

  // downsample to an exact integer c (7.5 * 0.8 = 6.0)
  items = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
  opt.emplace('h');
  auto ref_items = items; // copy to check contents
  ref_items.emplace_back('h'); // include partial item
  sample = ebpps_sample<char>(std::move(items), std::move(opt), 7.5);
  sample.downsample(0.8);
  REQUIRE(sample.get_c() == 6.0);
  REQUIRE(sample.get_num_retained_items() == 6);
  REQUIRE(sample.has_partial_item() == false);
  for (char c : sample) {
    REQUIRE(std::find(ref_items.begin(), ref_items.end(), c) != ref_items.end());
  }

  // downsample to c > 1 with partial item
  items = ref_items; // includes previous optional item
  opt.emplace('i');
  sample = ebpps_sample<char>(std::move(items), std::move(opt), 8.5);
  REQUIRE(sample.get_partial_item() == 'i');
  sample.downsample(0.8);
  REQUIRE(sample.get_c() == Approx(6.8).margin(EPS));
  REQUIRE(sample.get_num_retained_items() == 7);
  REQUIRE(sample.has_partial_item() == true);
  ref_items.emplace_back('i');
  for (char c : sample) {
    REQUIRE(std::find(ref_items.begin(), ref_items.end(), c) != ref_items.end());
  }

  random_utils::override_seed(random_utils::rd());
}

TEST_CASE("ebpps sample: merge unit samples", "[ebpps_sketch]") {
  uint32_t k = 8;
  ebpps_sample<int> sample = ebpps_sample<int>(k);
  
  ebpps_sample<int> s(1);
  for (uint32_t i = 1; i <= k; ++i) {
    s.replace_content(i, 1.0);
    sample.merge(s);
    REQUIRE(sample.get_c() == static_cast<double>(i));
    REQUIRE(sample.get_num_retained_items() == i);
  }

  sample.reset();
  REQUIRE(sample.get_c() == 0);
  REQUIRE(sample.get_num_retained_items() == 0);
  REQUIRE(sample.has_partial_item() == false);
}

} // namespace datasketches