libdpf/examples/evaluation/eval_sequence.cpp

115 lines
3.9 KiB
C++
Raw Normal View History

#include <array>
#include <cstdint>
#include <iostream>
#include "dpf.hpp"
/// A sorted point list. `return_output_only_tag_` stores one share per point.
/// A `sequence_recipe` compiled from that list is reusable across keys.
int main()
{
const std::uint8_t alpha = 42;
const std::uint64_t beta = 7;
auto [k0, k1] = dpf::make_dpf(alpha, beta);
using key_t = dpf::unwrap_party_key_t<std::decay_t<decltype(k0)>>;
//! [eval-sequence]
// Nondecreasing. An unsorted range throws std::runtime_error.
std::array<std::uint8_t, 5> points{1, 7, 42, 100, 200};
auto [buf0, iter0] = dpf::eval_sequence(k0, points.begin(), points.end(),
dpf::return_output_only_tag_{});
auto [buf1, iter1] = dpf::eval_sequence(k1, points.begin(), points.end(),
dpf::return_output_only_tag_{});
auto it0 = std::begin(iter0);
auto it1 = std::begin(iter1);
for (std::uint8_t x : points)
{
std::uint64_t got = dpf::reconstruct(*it0, *it1);
std::uint64_t expect = (x == alpha) ? beta : 0;
if (got != expect)
{
std::cerr << "eval_sequence\n";
return 1;
}
++it0;
++it1;
}
//! [eval-sequence]
//! [eval-sequence-recipe]
// The recipe is a property of the point list and the key's input type.
// Bind the memoizer to this recipe object and pass that same object back.
auto recipe = dpf::make_sequence_recipe<key_t>(points.begin(), points.end());
auto memo0 = dpf::make_double_space_sequence_memoizer<key_t>(recipe);
auto memo1 = dpf::make_double_space_sequence_memoizer<key_t>(recipe);
auto sbuf0 = dpf::make_output_buffer_for_recipe_subsequence(k0, recipe,
dpf::return_output_only_tag_{});
auto sbuf1 = dpf::make_output_buffer_for_recipe_subsequence(k1, recipe,
dpf::return_output_only_tag_{});
auto seq0 = dpf::eval_sequence(k0, recipe, sbuf0, memo0,
dpf::return_output_only_tag_{});
auto seq1 = dpf::eval_sequence(k1, recipe, sbuf1, memo1,
dpf::return_output_only_tag_{});
//! [eval-sequence-recipe]
// Omitting the memoizer allocates a double-space workspace for that call.
seq0 = dpf::eval_sequence(k0, recipe, sbuf0, dpf::return_output_only_tag_{});
seq1 = dpf::eval_sequence(k1, recipe, sbuf1, dpf::return_output_only_tag_{});
it0 = std::begin(seq0);
it1 = std::begin(seq1);
for (std::uint8_t x : points)
{
if (dpf::reconstruct(*it0, *it1) != ((x == alpha) ? beta : 0))
{
std::cerr << "eval_sequence recipe, default memoizer\n";
return 1;
}
++it0;
++it1;
}
seq0 = dpf::eval_sequence(k0, recipe, sbuf0, memo0, dpf::return_output_only_tag_{});
seq1 = dpf::eval_sequence(k1, recipe, sbuf1, memo1, dpf::return_output_only_tag_{});
it0 = std::begin(seq0);
it1 = std::begin(seq1);
for (std::uint8_t x : points)
{
std::uint64_t got = dpf::reconstruct(*it0, *it1);
std::uint64_t expect = (x == alpha) ? beta : 0;
if (got != expect)
{
std::cerr << "eval_sequence recipe\n";
return 1;
}
++it0;
++it1;
}
// Same recipe, same memoizers, same buffers: a second key overwrites them.
auto [k0b, k1b] = dpf::make_dpf(std::uint8_t{100}, std::uint64_t{9});
seq0 = dpf::eval_sequence(k0b, recipe, sbuf0, memo0, dpf::return_output_only_tag_{});
seq1 = dpf::eval_sequence(k1b, recipe, sbuf1, memo1, dpf::return_output_only_tag_{});
it0 = std::begin(seq0);
it1 = std::begin(seq1);
for (std::uint8_t x : points)
{
std::uint64_t got = dpf::reconstruct(*it0, *it1);
std::uint64_t expect = (x == 100) ? 9 : 0;
if (got != expect)
{
std::cerr << "eval_sequence recipe reuse\n";
return 1;
}
++it0;
++it1;
}
std::cout << beta << "\n";
(void)buf0;
(void)buf1;
return 0;
}