Checkpoint the party/runtime stack before share-program and malicious-mode work.
Ship the TLS mesh, composer, Beaver/Yao/leaf MPC, prep/online paths, apps, and docs so the tree is pushable before elevating share_expr, security_mode, and prep resume. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
695f8e84f7
commit
0d22946a0e
1835 changed files with 170291 additions and 2849 deletions
611
test/tests/defer_eval_test.cpp
Normal file
611
test/tests/defer_eval_test.cpp
Normal file
|
|
@ -0,0 +1,611 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
auto recon(const A & a, const B & b)
|
||||
{
|
||||
if constexpr (dpf::is_secret_share_v<std::decay_t<A>>
|
||||
&& dpf::is_secret_share_v<std::decay_t<B>>)
|
||||
return dpf::reconstruct(a, b);
|
||||
else
|
||||
{
|
||||
using T = std::common_type_t<std::decay_t<A>, std::decay_t<B>>;
|
||||
if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>)
|
||||
return static_cast<T>(a - b);
|
||||
else
|
||||
return a - b;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key0, typename Key1, typename InputT>
|
||||
void assign_input_local(Key0 & k0, Key1 & k1, InputT alpha)
|
||||
{
|
||||
using input_type = InputT;
|
||||
const input_type a0 = static_cast<input_type>(0x12);
|
||||
const input_type a1 = static_cast<input_type>(alpha - a0);
|
||||
const auto sh0 = k0.offset_x.compute_and_get_share(a0);
|
||||
const auto sh1 = k1.offset_x.compute_and_get_share(a1);
|
||||
k0.offset_x.reconstruct(sh1);
|
||||
k1.offset_x.reconstruct(sh0);
|
||||
}
|
||||
|
||||
template <typename Def0, typename Def1, typename Eager0, typename Eager1>
|
||||
void expect_recon_equal(Def0 && deferred0, Def1 && deferred1,
|
||||
Eager0 && eager0, Eager1 && eager1)
|
||||
{
|
||||
auto it_a = std::begin(deferred0);
|
||||
auto it_b = std::begin(deferred1);
|
||||
auto it_c = std::begin(eager0);
|
||||
auto it_d = std::begin(eager1);
|
||||
const auto end_a = std::end(deferred0);
|
||||
std::size_t n = 0;
|
||||
while (it_a != end_a)
|
||||
{
|
||||
ASSERT_NE(it_b, std::end(deferred1)) << "at index " << n;
|
||||
ASSERT_NE(it_c, std::end(eager0)) << "at index " << n;
|
||||
ASSERT_NE(it_d, std::end(eager1)) << "at index " << n;
|
||||
EXPECT_EQ(recon(*it_a, *it_b), recon(*it_c, *it_d)) << "at index " << n;
|
||||
++it_a;
|
||||
++it_b;
|
||||
++it_c;
|
||||
++it_d;
|
||||
++n;
|
||||
}
|
||||
EXPECT_EQ(it_b, std::end(deferred1));
|
||||
EXPECT_EQ(it_c, std::end(eager0));
|
||||
EXPECT_EQ(it_d, std::end(eager1));
|
||||
EXPECT_GT(n, std::size_t{0});
|
||||
}
|
||||
|
||||
template <typename InputT>
|
||||
std::size_t inclusive_span(InputT from, InputT to)
|
||||
{
|
||||
constexpr auto bits = dpf::utils::bitlength_of_v<InputT>;
|
||||
constexpr auto to_int = dpf::utils::to_integral_type<InputT>{};
|
||||
auto span = to_int(to) - to_int(from);
|
||||
if constexpr (bits < dpf::utils::bitlength_of_v<decltype(span)>)
|
||||
span &= (decltype(span){1} << bits) - 1;
|
||||
return static_cast<std::size_t>(span) + 1;
|
||||
}
|
||||
|
||||
template <typename View0, typename View1, typename InputT, typename OutputT>
|
||||
void expect_point_mass(View0 && v0, View1 && v1, InputT from, InputT to,
|
||||
InputT alpha, OutputT beta)
|
||||
{
|
||||
auto it0 = std::begin(v0);
|
||||
auto it1 = std::begin(v1);
|
||||
bool saw = false;
|
||||
InputT x = from;
|
||||
for (std::size_t i = 0; i < inclusive_span(from, to); ++i)
|
||||
{
|
||||
ASSERT_NE(it0, std::end(v0));
|
||||
ASSERT_NE(it1, std::end(v1));
|
||||
const auto y = recon(*it0, *it1);
|
||||
if (x == alpha)
|
||||
{
|
||||
EXPECT_EQ(y, beta) << "x=" << +x;
|
||||
saw = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EQ(y, OutputT{0}) << "x=" << +x;
|
||||
}
|
||||
++it0;
|
||||
++it1;
|
||||
++x;
|
||||
}
|
||||
EXPECT_EQ(it0, std::end(v0));
|
||||
EXPECT_EQ(it1, std::end(v1));
|
||||
bool expect_hit = false;
|
||||
if constexpr (std::is_unsigned_v<InputT>)
|
||||
{
|
||||
if (from <= to)
|
||||
expect_hit = (alpha >= from && alpha <= to);
|
||||
else
|
||||
expect_hit = (alpha >= from) || (alpha <= to);
|
||||
}
|
||||
else
|
||||
{
|
||||
expect_hit = (alpha >= from && alpha <= to);
|
||||
}
|
||||
EXPECT_EQ(saw, expect_hit);
|
||||
}
|
||||
|
||||
template <typename Key0, typename Key1, typename InputT, typename OutputT>
|
||||
void compare_deferred_interval(Key0 & d0, Key1 & d1, InputT from, InputT to,
|
||||
InputT alpha, OutputT beta)
|
||||
{
|
||||
auto buf0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto buf1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto deferred0 = dpf::defer_eval_interval(d0, from, to, buf0);
|
||||
auto deferred1 = dpf::defer_eval_interval(d1, from, to, buf1);
|
||||
|
||||
assign_input_local(d0, d1, alpha);
|
||||
|
||||
auto eager_buf0 = dpf::make_output_buffer_for_interval(d0, from, to);
|
||||
auto eager_buf1 = dpf::make_output_buffer_for_interval(d1, from, to);
|
||||
auto eager_memo0 = dpf::make_basic_full_memoizer(d0);
|
||||
auto eager_memo1 = dpf::make_basic_full_memoizer(d1);
|
||||
auto eager0 = dpf::eval_interval(d0, from, to, eager_buf0, eager_memo0);
|
||||
auto eager1 = dpf::eval_interval(d1, from, to, eager_buf1, eager_memo1);
|
||||
|
||||
auto view0 = deferred0.get();
|
||||
auto view1 = deferred1.get();
|
||||
expect_recon_equal(view0, view1, eager0, eager1);
|
||||
expect_point_mass(view0, view1, from, to, alpha, beta);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Happy paths already covered lightly; keep regressions + expand corners.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST(DeferEvalTest, IntervalMatchesEagerAfterAssignUint8)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint32_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{7});
|
||||
compare_deferred_interval(d0, d1, input_type{0x10}, input_type{0x40},
|
||||
input_type{0x2A}, output_type{7});
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, FullMatchesEagerAfterAssignUint8)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint64_t;
|
||||
constexpr output_type beta{0x1111};
|
||||
constexpr input_type alpha{0x33};
|
||||
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{}, beta);
|
||||
auto buf0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto buf1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto deferred0 = dpf::defer_eval_full(d0, buf0);
|
||||
auto deferred1 = dpf::defer_eval_full(d1, buf1);
|
||||
assign_input_local(d0, d1, alpha);
|
||||
|
||||
auto eager_buf0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto eager_buf1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto eager0 = dpf::eval_full(d0, eager_buf0);
|
||||
auto eager1 = dpf::eval_full(d1, eager_buf1);
|
||||
auto view0 = deferred0.get();
|
||||
auto view1 = deferred1.get();
|
||||
expect_recon_equal(view0, view1, eager0, eager1);
|
||||
expect_point_mass(view0, view1,
|
||||
std::numeric_limits<input_type>::min(),
|
||||
std::numeric_limits<input_type>::max(), alpha, beta);
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, IntervalMatchesEagerAfterAssignSigned)
|
||||
{
|
||||
using input_type = std::int8_t;
|
||||
using output_type = std::uint32_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{9});
|
||||
compare_deferred_interval(d0, d1, input_type{-40}, input_type{10},
|
||||
input_type{-20}, output_type{9});
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, MultiOutputLeafMatchesEager)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint64_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{0xABCDEF0123456789ull});
|
||||
ASSERT_GT(decltype(d0)::outputs_per_leaf, std::size_t{1});
|
||||
compare_deferred_interval(d0, d1, input_type{0x70}, input_type{0x8F},
|
||||
input_type{0x7E}, output_type{0xABCDEF0123456789ull});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Assert / misuse corners
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST(DeferEvalTest, GetBeforeAssignThrows)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{1});
|
||||
(void)d1;
|
||||
auto buf = dpf::make_output_buffer_for_full(d0);
|
||||
auto deferred = dpf::defer_eval_interval(d0, input_type{0}, input_type{3},
|
||||
buf);
|
||||
EXPECT_THROW(static_cast<void>(deferred.get()), std::runtime_error);
|
||||
EXPECT_THROW(static_cast<void>(deferred.begin()), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, DeferAfterAssignThrows)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{1});
|
||||
assign_input_local(d0, d1, input_type{9});
|
||||
auto buf = dpf::make_output_buffer_for_full(d0);
|
||||
EXPECT_THROW(
|
||||
static_cast<void>(dpf::defer_eval_interval(d0, input_type{0},
|
||||
input_type{3}, buf)),
|
||||
std::runtime_error);
|
||||
EXPECT_THROW(static_cast<void>(dpf::defer_eval_full(d0, buf)),
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, EagerEvalBeforeAssignThrows)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{1});
|
||||
(void)d1;
|
||||
EXPECT_THROW(static_cast<void>(dpf::eval_point(d0, input_type{0})),
|
||||
std::runtime_error);
|
||||
EXPECT_THROW(static_cast<void>(dpf::eval_interval(d0, input_type{0},
|
||||
input_type{1})),
|
||||
std::runtime_error);
|
||||
EXPECT_THROW(static_cast<void>(dpf::eval_full(d0)), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, DeferTraverseIntervalRequiresAssignedInput)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{1});
|
||||
auto memo = dpf::make_basic_full_memoizer(d0);
|
||||
EXPECT_THROW(
|
||||
dpf::defer_traverse_interval(d0, input_type{0}, input_type{10}, memo),
|
||||
std::runtime_error);
|
||||
assign_input_local(d0, d1, input_type{4});
|
||||
EXPECT_NO_THROW(
|
||||
dpf::defer_traverse_interval(d0, input_type{0}, input_type{10}, memo));
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, DeferTraverseFullAllowsUnassignedInput)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{3});
|
||||
auto memo0 = dpf::make_basic_full_memoizer(d0);
|
||||
auto memo1 = dpf::make_basic_full_memoizer(d1);
|
||||
EXPECT_NO_THROW(dpf::defer_traverse_full(d0, memo0));
|
||||
EXPECT_NO_THROW(dpf::defer_traverse_full(d1, memo1));
|
||||
assign_input_local(d0, d1, input_type{0x55});
|
||||
EXPECT_EQ(recon(*dpf::eval_point(d0, input_type{0x55}),
|
||||
*dpf::eval_point(d1, input_type{0x55})),
|
||||
std::uint32_t{3});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Boundary / length / caching
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST(DeferEvalTest, SinglePointInterval)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint32_t;
|
||||
constexpr input_type alpha{0x77};
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{42});
|
||||
compare_deferred_interval(d0, d1, alpha, alpha, alpha, output_type{42});
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, SpikeAtFromAndToBoundaries)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint32_t;
|
||||
{
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{5});
|
||||
compare_deferred_interval(d0, d1, input_type{0x20}, input_type{0x30},
|
||||
input_type{0x20}, output_type{5});
|
||||
}
|
||||
{
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{6});
|
||||
compare_deferred_interval(d0, d1, input_type{0x20}, input_type{0x30},
|
||||
input_type{0x30}, output_type{6});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, SpikeOutsideIntervalIsZero)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint32_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{99});
|
||||
compare_deferred_interval(d0, d1, input_type{0x10}, input_type{0x20},
|
||||
input_type{0x80}, output_type{99});
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, ViewLengthMatchesInclusiveSpan)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{1});
|
||||
constexpr input_type from{5};
|
||||
constexpr input_type to{12};
|
||||
auto buf0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto buf1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto deferred0 = dpf::defer_eval_interval(d0, from, to, buf0);
|
||||
auto deferred1 = dpf::defer_eval_interval(d1, from, to, buf1);
|
||||
assign_input_local(d0, d1, input_type{7});
|
||||
auto view0 = deferred0.get();
|
||||
auto view1 = deferred1.get();
|
||||
EXPECT_EQ(static_cast<std::size_t>(std::distance(std::begin(view0),
|
||||
std::end(view0))),
|
||||
inclusive_span(from, to));
|
||||
EXPECT_EQ(static_cast<std::size_t>(std::distance(std::begin(view1),
|
||||
std::end(view1))),
|
||||
inclusive_span(from, to));
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, GetCachesRotationSecondCallMatches)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{11});
|
||||
auto buf0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto buf1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto deferred0 = dpf::defer_eval_interval(d0, input_type{1}, input_type{20},
|
||||
buf0);
|
||||
auto deferred1 = dpf::defer_eval_interval(d1, input_type{1}, input_type{20},
|
||||
buf1);
|
||||
assign_input_local(d0, d1, input_type{9});
|
||||
auto a0 = deferred0.get();
|
||||
auto a1 = deferred1.get();
|
||||
auto b0 = deferred0.get();
|
||||
auto b1 = deferred1.get();
|
||||
expect_recon_equal(a0, a1, b0, b1);
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, BeginEndOnDeferredObject)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{2});
|
||||
auto buf0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto buf1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto deferred0 = dpf::defer_eval_interval(d0, input_type{0}, input_type{4},
|
||||
buf0);
|
||||
auto deferred1 = dpf::defer_eval_interval(d1, input_type{0}, input_type{4},
|
||||
buf1);
|
||||
assign_input_local(d0, d1, input_type{2});
|
||||
std::size_t n = 0;
|
||||
auto it0 = deferred0.begin();
|
||||
auto it1 = deferred1.begin();
|
||||
for (; it0 != deferred0.end(); ++it0, ++it1, ++n)
|
||||
(void)recon(*it0, *it1);
|
||||
EXPECT_EQ(it1, deferred1.end());
|
||||
EXPECT_EQ(n, inclusive_span(input_type{0}, input_type{4}));
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, DeferEvalIntervalMinMaxMatchesDeferFull)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint32_t;
|
||||
constexpr output_type beta{13};
|
||||
constexpr input_type alpha{0x01};
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{}, beta);
|
||||
|
||||
auto buf_i0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto buf_i1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto buf_f0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto buf_f1 = dpf::make_output_buffer_for_full(d1);
|
||||
|
||||
auto as_interval0 = dpf::defer_eval_interval(d0,
|
||||
std::numeric_limits<input_type>::min(),
|
||||
std::numeric_limits<input_type>::max(), buf_i0);
|
||||
auto as_interval1 = dpf::defer_eval_interval(d1,
|
||||
std::numeric_limits<input_type>::min(),
|
||||
std::numeric_limits<input_type>::max(), buf_i1);
|
||||
auto as_full0 = dpf::defer_eval_full(d0, buf_f0);
|
||||
auto as_full1 = dpf::defer_eval_full(d1, buf_f1);
|
||||
|
||||
assign_input_local(d0, d1, alpha);
|
||||
expect_recon_equal(as_interval0.get(), as_interval1.get(),
|
||||
as_full0.get(), as_full1.get());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Wrapping intervals and offset stress
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST(DeferEvalTest, WrappingLogicalIntervalUint8)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint32_t;
|
||||
// [200, 10] wraps across 0.
|
||||
constexpr input_type from{200};
|
||||
constexpr input_type to{10};
|
||||
ASSERT_GT(from, to);
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{8});
|
||||
compare_deferred_interval(d0, d1, from, to, input_type{250},
|
||||
output_type{8});
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, WrappingIntervalSpikeInLowHalf)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{4});
|
||||
compare_deferred_interval(d0, d1, input_type{200}, input_type{10},
|
||||
input_type{5}, std::uint32_t{4});
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, ManyRandomOffsetsMatchEager)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint32_t;
|
||||
constexpr input_type from{30};
|
||||
constexpr input_type to{90};
|
||||
constexpr output_type beta{77};
|
||||
|
||||
// Sweep alphas; each keygen draws a fresh mask so offsets differ.
|
||||
for (unsigned a = 0; a < 256; a += 17)
|
||||
{
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{}, beta);
|
||||
compare_deferred_interval(d0, d1, from, to,
|
||||
static_cast<input_type>(a), beta);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, SignedFullDomain)
|
||||
{
|
||||
using input_type = std::int8_t;
|
||||
using output_type = std::uint32_t;
|
||||
constexpr output_type beta{21};
|
||||
constexpr input_type alpha{-128};
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{}, beta);
|
||||
auto buf0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto buf1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto deferred0 = dpf::defer_eval_full(d0, buf0);
|
||||
auto deferred1 = dpf::defer_eval_full(d1, buf1);
|
||||
assign_input_local(d0, d1, alpha);
|
||||
auto eager_buf0 = dpf::make_output_buffer_for_full(d0);
|
||||
auto eager_buf1 = dpf::make_output_buffer_for_full(d1);
|
||||
auto eager0 = dpf::eval_full(d0, eager_buf0);
|
||||
auto eager1 = dpf::eval_full(d1, eager_buf1);
|
||||
expect_recon_equal(deferred0.get(), deferred1.get(), eager0, eager1);
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, SignedSpanCrossingZero)
|
||||
{
|
||||
using input_type = std::int8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{3});
|
||||
compare_deferred_interval(d0, d1, input_type{-5}, input_type{5},
|
||||
input_type{0}, std::uint32_t{3});
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, UnalignedMultiOutputLeafInterval)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using output_type = std::uint64_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
output_type{0x55});
|
||||
ASSERT_GT(decltype(d0)::outputs_per_leaf, std::size_t{1});
|
||||
// Odd endpoints: not leaf-aligned when opl == 2.
|
||||
compare_deferred_interval(d0, d1, input_type{0x11}, input_type{0x2A},
|
||||
input_type{0x1F}, output_type{0x55});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Multi-output keys
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST(DeferEvalTest, TwoOutputSlotsIndependent)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
using out0 = std::uint32_t;
|
||||
using out1 = std::uint32_t;
|
||||
constexpr input_type alpha{0x44};
|
||||
constexpr out0 beta0{100};
|
||||
constexpr out1 beta1{200};
|
||||
constexpr input_type from{0x40};
|
||||
constexpr input_type to{0x50};
|
||||
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{}, beta0,
|
||||
beta1);
|
||||
|
||||
auto bufs0 = dpf::make_output_buffer_for_full<0, 1>(d0);
|
||||
auto bufs1 = dpf::make_output_buffer_for_full<0, 1>(d1);
|
||||
auto def0 = dpf::defer_eval_interval<0, 1>(d0, from, to, bufs0);
|
||||
auto def1 = dpf::defer_eval_interval<0, 1>(d1, from, to, bufs1);
|
||||
|
||||
assign_input_local(d0, d1, alpha);
|
||||
|
||||
auto eager_bufs0 = dpf::make_output_buffer_for_interval<0, 1>(d0, from, to);
|
||||
auto eager_bufs1 = dpf::make_output_buffer_for_interval<0, 1>(d1, from, to);
|
||||
auto memo0 = dpf::make_basic_full_memoizer(d0);
|
||||
auto memo1 = dpf::make_basic_full_memoizer(d1);
|
||||
auto eager0 = dpf::eval_interval<0, 1>(d0, from, to, eager_bufs0, memo0);
|
||||
auto eager1 = dpf::eval_interval<0, 1>(d1, from, to, eager_bufs1, memo1);
|
||||
|
||||
expect_recon_equal(std::get<0>(def0).get(), std::get<0>(def1).get(),
|
||||
std::get<0>(eager0), std::get<0>(eager1));
|
||||
expect_recon_equal(std::get<1>(def0).get(), std::get<1>(def1).get(),
|
||||
std::get<1>(eager0), std::get<1>(eager1));
|
||||
|
||||
expect_point_mass(std::get<0>(def0).get(), std::get<0>(def1).get(),
|
||||
from, to, alpha, beta0);
|
||||
expect_point_mass(std::get<1>(def0).get(), std::get<1>(def1).get(),
|
||||
from, to, alpha, beta1);
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, SelectSecondOutputOnly)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
constexpr input_type alpha{0x08};
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{1}, std::uint32_t{99});
|
||||
|
||||
auto buf0 = dpf::make_output_buffer_for_full<1>(d0);
|
||||
auto buf1 = dpf::make_output_buffer_for_full<1>(d1);
|
||||
auto def0 = dpf::defer_eval_interval<1>(d0, input_type{0}, input_type{15},
|
||||
buf0);
|
||||
auto def1 = dpf::defer_eval_interval<1>(d1, input_type{0}, input_type{15},
|
||||
buf1);
|
||||
assign_input_local(d0, d1, alpha);
|
||||
|
||||
auto eager_buf0 = dpf::make_output_buffer_for_interval<1>(d0, input_type{0},
|
||||
input_type{15});
|
||||
auto eager_buf1 = dpf::make_output_buffer_for_interval<1>(d1, input_type{0},
|
||||
input_type{15});
|
||||
auto memo0 = dpf::make_basic_full_memoizer(d0);
|
||||
auto memo1 = dpf::make_basic_full_memoizer(d1);
|
||||
auto eager0 = dpf::eval_interval<1>(d0, input_type{0}, input_type{15},
|
||||
eager_buf0, memo0);
|
||||
auto eager1 = dpf::eval_interval<1>(d1, input_type{0}, input_type{15},
|
||||
eager_buf1, memo1);
|
||||
expect_recon_equal(def0.get(), def1.get(), eager0, eager1);
|
||||
expect_point_mass(def0.get(), def1.get(), input_type{0}, input_type{15},
|
||||
alpha, std::uint32_t{99});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Metadata on the deferred object
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST(DeferEvalTest, DeferredStoresFromToAndKey)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{1});
|
||||
(void)d1;
|
||||
auto buf = dpf::make_output_buffer_for_full(d0);
|
||||
auto deferred = dpf::defer_eval_interval(d0, input_type{3}, input_type{9},
|
||||
buf);
|
||||
EXPECT_EQ(deferred.from(), input_type{3});
|
||||
EXPECT_EQ(deferred.to(), input_type{9});
|
||||
EXPECT_EQ(&deferred.dpf(), &d0);
|
||||
}
|
||||
|
||||
TEST(DeferEvalTest, DomainMinMaxSpike)
|
||||
{
|
||||
using input_type = std::uint8_t;
|
||||
{
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{1});
|
||||
compare_deferred_interval(d0, d1, input_type{0}, input_type{255},
|
||||
input_type{0}, std::uint32_t{1});
|
||||
}
|
||||
{
|
||||
auto [d0, d1] = dpf::make_dpf(dpf::wildcard_value<input_type>{},
|
||||
std::uint32_t{2});
|
||||
compare_deferred_interval(d0, d1, input_type{0}, input_type{255},
|
||||
input_type{255}, std::uint32_t{2});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue