Initial import of libdpf.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
commit
e4e666f459
4563 changed files with 1690372 additions and 0 deletions
35
test/tests/advice_bit_iterable_test.cpp
Normal file
35
test/tests/advice_bit_iterable_test.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
TEST(AdviceBitIterableTest, BasicUsage)
|
||||
{
|
||||
using input_type = uint16_t;
|
||||
using output_type = dpf::bit;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
input_type x = 0xAAAA;
|
||||
output_type y = dpf::bit::one;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_full(dpf0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_full(dpf1, memo1);
|
||||
|
||||
auto advice0 = dpf::advice_bits_of(memo0),
|
||||
advice1 = dpf::advice_bits_of(memo1);
|
||||
|
||||
auto it0 = std::begin(advice0), it1 = std::begin(advice1);
|
||||
for (std::size_t i = 0; i < std::size_t(1)<<dpf_type::depth; ++i, ++it0, ++it1)
|
||||
{
|
||||
if (i == x/dpf_type::outputs_per_leaf)
|
||||
{
|
||||
ASSERT_NE(*it0, *it1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(*it0, *it1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(advice0));
|
||||
ASSERT_EQ(it1, std::end(advice1));
|
||||
}
|
||||
24
test/tests/all_test.cpp
Normal file
24
test/tests/all_test.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include <cstdlib>
|
||||
|
||||
int main()
|
||||
{
|
||||
system("./bin/dpf_key_test");
|
||||
system("./bin/wildcard_test");
|
||||
|
||||
system("./bin/eval_point_test");
|
||||
system("./bin/eval_interval_test");
|
||||
system("./bin/eval_full_test");
|
||||
system("./bin/eval_sequence_test");
|
||||
|
||||
system("./bin/eval_point_multi_test");
|
||||
system("./bin/eval_interval_multi_test");
|
||||
system("./bin/eval_full_multi_test");
|
||||
system("./bin/eval_sequence_multi_test");
|
||||
|
||||
system("./bin/advice_bit_iterable_test");
|
||||
system("./bin/parallel_bit_iterable_test");
|
||||
system("./bin/setbit_index_iterable_test");
|
||||
system("./bin/keyword2_test");
|
||||
|
||||
return 0;
|
||||
}
|
||||
626
test/tests/beaver_test.cpp
Normal file
626
test/tests/beaver_test.cpp
Normal file
|
|
@ -0,0 +1,626 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "dpf/beaver.hpp"
|
||||
#include "dpf/buffered_prg.hpp"
|
||||
#include "dpf/modint.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Counter
|
||||
{
|
||||
int draws = 0;
|
||||
|
||||
std::uint64_t operator()()
|
||||
{
|
||||
++draws;
|
||||
return 0x9e3779b97f4a7c15ull * static_cast<std::uint64_t>(draws);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Ring>
|
||||
struct Seq
|
||||
{
|
||||
unsigned n = 1;
|
||||
|
||||
Ring operator()()
|
||||
{
|
||||
return Ring{static_cast<typename Ring::integral_type>(n++ * 17u + 3u)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Ring>
|
||||
struct XorSeq
|
||||
{
|
||||
unsigned n = 1;
|
||||
|
||||
Ring operator()()
|
||||
{
|
||||
using u = typename Ring::value_type;
|
||||
return Ring{static_cast<u>(n++ * 0x9e3779b9u)};
|
||||
}
|
||||
};
|
||||
|
||||
using u64 = std::uint64_t;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Beaver, ProductTwo)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto z = s(x * y);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(rng.draws, 5); // two input blinds * 2 draws + one product share
|
||||
EXPECT_EQ(s.monomial_count(), 1u);
|
||||
EXPECT_EQ(s.round_of(z), 1);
|
||||
EXPECT_EQ(s.monomial({{x, 1u}, {y, 1u}}).open(),
|
||||
s.lambda(x).open() * s.lambda(y).open());
|
||||
|
||||
s.bind(x, u64{7}, rng);
|
||||
s.bind(y, u64{9}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z), 63u);
|
||||
EXPECT_EQ(s.delta(x), u64{7} + s.lambda(x).open());
|
||||
EXPECT_EQ(dpf::reconstruct(s.value(z).party0(), s.value(z).party1()), 63u);
|
||||
EXPECT_NE(s.value(z).p0, s.open(z));
|
||||
}
|
||||
|
||||
TEST(Beaver, ProductThreeAndSquare)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto a = s.input();
|
||||
auto b = s.input();
|
||||
auto c = s.input();
|
||||
auto p = s.product(a, b, c);
|
||||
auto sq = s(b * b);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
// wires a,b,c,p,sq = 5 * 2, monomials of a*b*c are the three pairs + abc
|
||||
// (singletons live on the wires), plus λb²
|
||||
EXPECT_EQ(s.monomial_count(), 5u);
|
||||
EXPECT_EQ(s.round_of(p), 1);
|
||||
EXPECT_EQ(s.round_of(sq), 1);
|
||||
s.bind(a, u64{2}, rng);
|
||||
s.bind(b, u64{3}, rng);
|
||||
s.bind(c, u64{5}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(p), 30u);
|
||||
EXPECT_EQ(s.open(sq), 9u);
|
||||
}
|
||||
|
||||
TEST(Beaver, MulSquareIsOneRound)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto a = s.input();
|
||||
auto x = s.input();
|
||||
auto z = s(a * x * x);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(s.round_of(z), 1);
|
||||
EXPECT_EQ(s.wire_count(), 3u);
|
||||
// λx², λa λx, λa λx². One blind for both x factors.
|
||||
EXPECT_EQ(s.monomial_count(), 3u);
|
||||
EXPECT_EQ(rng.draws, 7); // two input blinds * 2 + three product shares
|
||||
EXPECT_EQ(s.monomial({{x, 2u}}).open(),
|
||||
s.lambda(x).open() * s.lambda(x).open());
|
||||
EXPECT_EQ(s.monomial({{a, 1u}, {x, 2u}}).open(),
|
||||
s.lambda(a).open() * s.lambda(x).open() * s.lambda(x).open());
|
||||
s.bind(a, u64{4}, rng);
|
||||
s.bind(x, u64{5}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z), 100u);
|
||||
}
|
||||
|
||||
TEST(Beaver, ChainedSquareUsesTwoRounds)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto a = s.input();
|
||||
auto x = s.input();
|
||||
auto x2 = s(x * x);
|
||||
auto z = s(a * x2);
|
||||
EXPECT_EQ(s.round_of(x2), 1);
|
||||
EXPECT_EQ(s.round_of(z), 2);
|
||||
EXPECT_EQ(s.monomial_count(), 2u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(a, u64{4}, rng);
|
||||
s.bind(x, u64{5}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(x2), 25u);
|
||||
EXPECT_EQ(s.open(z), 100u);
|
||||
}
|
||||
|
||||
TEST(Beaver, DotAggregatesCrossTerm)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto x0 = s.input();
|
||||
auto x1 = s.input();
|
||||
auto x2 = s.input();
|
||||
auto y0 = s.input();
|
||||
auto y1 = s.input();
|
||||
auto y2 = s.input();
|
||||
auto z = s.dot({x0, x1, x2}, {y0, y1, y2});
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(s.monomial_count(), 0u);
|
||||
EXPECT_EQ(s.round_of(z), 1);
|
||||
// 6 input blinds, two draws each, plus one aggregated cross draw
|
||||
EXPECT_EQ(rng.draws, 13);
|
||||
auto cross = s.lambda(x0).open() * s.lambda(y0).open()
|
||||
+ s.lambda(x1).open() * s.lambda(y1).open()
|
||||
+ s.lambda(x2).open() * s.lambda(y2).open();
|
||||
EXPECT_EQ(s.dot_cross(z).open(), cross);
|
||||
s.bind(x0, u64{1}, rng);
|
||||
s.bind(x1, u64{2}, rng);
|
||||
s.bind(x2, u64{3}, rng);
|
||||
s.bind(y0, u64{4}, rng);
|
||||
s.bind(y1, u64{5}, rng);
|
||||
s.bind(y2, u64{6}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z), 32u);
|
||||
}
|
||||
|
||||
TEST(Beaver, DotReusesAPair)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto a = s.input();
|
||||
auto b = s.input();
|
||||
auto z = s.dot({a, a}, {b, b});
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(s.monomial_count(), 0u);
|
||||
s.bind(a, u64{3}, rng);
|
||||
s.bind(b, u64{4}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z), 24u);
|
||||
}
|
||||
|
||||
TEST(Beaver, ScaleSharesScalarBlind)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto scalar = s.input();
|
||||
auto v0 = s.input();
|
||||
auto v1 = s.input();
|
||||
auto v2 = s.input();
|
||||
auto v3 = s.input();
|
||||
auto z = s.scale(scalar, {v0, v1, v2, v3});
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(z.size(), 4u);
|
||||
EXPECT_EQ(s.monomial_count(), 4u);
|
||||
EXPECT_EQ(s.round_of(z[0]), 1);
|
||||
// 1 scalar + 4 lanes + 4 outputs = 9 wires * 2, plus 4 cross terms
|
||||
EXPECT_EQ(rng.draws, 14);
|
||||
s.bind(scalar, u64{9}, rng);
|
||||
s.bind(v0, u64{0}, rng);
|
||||
s.bind(v1, u64{1}, rng);
|
||||
s.bind(v2, u64{0}, rng);
|
||||
s.bind(v3, u64{0}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z[0]), 0u);
|
||||
EXPECT_EQ(s.open(z[1]), 9u);
|
||||
EXPECT_EQ(s.open(z[2]), 0u);
|
||||
EXPECT_EQ(s.open(z[3]), 0u);
|
||||
}
|
||||
|
||||
TEST(Beaver, ScaleDedupsARepeatedLane)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto scalar = s.input();
|
||||
auto v = s.input();
|
||||
auto z = s.scale(scalar, {v, v});
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(s.monomial_count(), 1u);
|
||||
EXPECT_EQ(rng.draws, 5);
|
||||
s.bind(scalar, u64{6}, rng);
|
||||
s.bind(v, u64{7}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z[0]), 42u);
|
||||
EXPECT_EQ(s.open(z[1]), 42u);
|
||||
}
|
||||
|
||||
TEST(Beaver, BitMulAndMux)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto b = s.bit();
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto prod = s.bit_mul(b, x);
|
||||
auto picked = s.mux(b, x, y);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(b, u64{1}, rng);
|
||||
s.bind(x, u64{42}, rng);
|
||||
s.bind(y, u64{7}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(prod), 42u);
|
||||
EXPECT_EQ(s.open(picked), 42u);
|
||||
EXPECT_EQ(s.round_of(prod), 1);
|
||||
EXPECT_EQ(s.round_of(picked), 1);
|
||||
|
||||
dpf::beavers::session<u64> t;
|
||||
auto b0 = t.bit();
|
||||
auto x0 = t.input();
|
||||
auto y0 = t.input();
|
||||
auto prod0 = t.bit_mul(b0, x0);
|
||||
auto picked0 = t.mux(b0, x0, y0);
|
||||
t.sample(rng);
|
||||
t.bind(b0, u64{0}, rng);
|
||||
t.bind(x0, u64{42}, rng);
|
||||
t.bind(y0, u64{7}, rng);
|
||||
t.evaluate();
|
||||
EXPECT_EQ(t.open(prod0), 0u);
|
||||
EXPECT_EQ(t.open(picked0), 7u);
|
||||
}
|
||||
|
||||
TEST(Beaver, BatchOneRoundSharesOperands)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto z = s.input();
|
||||
auto xy = s(x * y);
|
||||
auto yz = s(y * z);
|
||||
auto xx = s(x * x);
|
||||
EXPECT_EQ(s.monomial_count(), 3u);
|
||||
EXPECT_EQ(s.round_of(xy), 1);
|
||||
EXPECT_EQ(s.round_of(yz), 1);
|
||||
EXPECT_EQ(s.round_of(xx), 1);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(rng.draws, 9);
|
||||
s.bind(x, u64{2}, rng);
|
||||
s.bind(y, u64{3}, rng);
|
||||
s.bind(z, u64{5}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(xy), 6u);
|
||||
EXPECT_EQ(s.open(yz), 15u);
|
||||
EXPECT_EQ(s.open(xx), 4u);
|
||||
// y's blind was opened once and serves both products
|
||||
EXPECT_EQ(s.delta(y), u64{3} + s.lambda(y).open());
|
||||
}
|
||||
|
||||
TEST(Beaver, BlindSurvivesALaterRound)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto xy = s(x * y);
|
||||
s.pin(xy);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
auto lx = s.lambda(x);
|
||||
int draws = rng.draws;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(rng.draws, draws);
|
||||
EXPECT_EQ(s.lambda(x), lx);
|
||||
s.bind(x, u64{4}, rng);
|
||||
s.bind(y, u64{5}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(xy), 20u);
|
||||
auto lxy = s.lambda(xy);
|
||||
draws = rng.draws;
|
||||
|
||||
// Next batch: z is new, xy already has a blind. Depth is 2.
|
||||
auto z = s.input();
|
||||
auto xyz = s(xy * z);
|
||||
EXPECT_EQ(s.round_of(xyz), 2);
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(s.lambda(x), lx);
|
||||
EXPECT_EQ(s.lambda(xy), lxy);
|
||||
EXPECT_EQ(s.monomial_count(), 2u);
|
||||
// z's blind (2 draws) and one new product λ_xy λ_z
|
||||
EXPECT_EQ(rng.draws, draws + 3);
|
||||
s.bind(z, u64{6}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(xy), 20u);
|
||||
EXPECT_EQ(s.open(xyz), 120u);
|
||||
EXPECT_EQ(s.lambda(x), lx);
|
||||
}
|
||||
|
||||
TEST(Beaver, XorWrapperAndMux)
|
||||
{
|
||||
using W = dpf::xor_wrapper<std::uint32_t>;
|
||||
dpf::beavers::session<W> s;
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto bit = s.bit();
|
||||
auto prod = s(x * y);
|
||||
auto sq = s(x * x);
|
||||
auto picked = s.mux(bit, x, y);
|
||||
XorSeq<W> rng;
|
||||
s.sample(rng);
|
||||
s.bind(x, W{0b1100u}, rng);
|
||||
s.bind(y, W{0b1010u}, rng);
|
||||
s.bind(bit, dpf::beavers::ring_traits<W>::one(), rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(prod), W{0b1000u});
|
||||
EXPECT_EQ(s.open(sq), W{0b1100u});
|
||||
EXPECT_EQ(s.open(picked), W{0b1100u});
|
||||
}
|
||||
|
||||
TEST(Beaver, ModintProduct)
|
||||
{
|
||||
using M = dpf::modint<17>;
|
||||
dpf::beavers::session<M> s;
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto z = s.mul_square(x, y);
|
||||
Seq<M> rng;
|
||||
s.sample(rng);
|
||||
s.bind(x, M{6}, rng);
|
||||
s.bind(y, M{5}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(static_cast<M::integral_type>(s.open(z)),
|
||||
static_cast<M::integral_type>(M{6} * M{5} * M{5}));
|
||||
}
|
||||
|
||||
TEST(Beaver, OneShotTriplesMatchProducts)
|
||||
{
|
||||
Counter rng;
|
||||
auto p2 = dpf::beavers::sample_beaver2<u64>(rng);
|
||||
EXPECT_EQ(p2.ab.open(), p2.a.open() * p2.b.open());
|
||||
|
||||
auto p3 = dpf::beavers::sample_beaver3<u64>(rng);
|
||||
EXPECT_EQ(p3.ab.open(), p3.a.open() * p3.b.open());
|
||||
EXPECT_EQ(p3.ac.open(), p3.a.open() * p3.c.open());
|
||||
EXPECT_EQ(p3.bc.open(), p3.b.open() * p3.c.open());
|
||||
EXPECT_EQ(p3.abc.open(), p3.a.open() * p3.b.open() * p3.c.open());
|
||||
|
||||
auto sq = dpf::beavers::sample_square<u64>(rng);
|
||||
EXPECT_EQ(sq.x2.open(), sq.x.open() * sq.x.open());
|
||||
|
||||
auto ax = dpf::beavers::sample_mul_square<u64>(rng);
|
||||
EXPECT_EQ(ax.x2.open(), ax.x.open() * ax.x.open());
|
||||
EXPECT_EQ(ax.ax.open(), ax.a.open() * ax.x.open());
|
||||
EXPECT_EQ(ax.ax2.open(), ax.a.open() * ax.x.open() * ax.x.open());
|
||||
|
||||
auto dot = dpf::beavers::sample_dot<u64>(3, rng);
|
||||
u64 cross = 0;
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
cross += dot.x[i].open() * dot.y[i].open();
|
||||
EXPECT_EQ(dot.cross.open(), cross);
|
||||
|
||||
auto sc = dpf::beavers::sample_scale<u64>(3, rng);
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
EXPECT_EQ(sc.cross[i].open(), sc.scalar.open() * sc.lanes[i].open());
|
||||
|
||||
auto bm = dpf::beavers::sample_bit_mul<u64>(rng);
|
||||
EXPECT_EQ(bm.product.open(), bm.bit.open() * bm.scalar.open());
|
||||
|
||||
auto mx = dpf::beavers::sample_mux<u64>(rng);
|
||||
EXPECT_EQ(mx.bit_when1.open(), mx.bit.open() * mx.when1.open());
|
||||
EXPECT_EQ(mx.bit_when0.open(), mx.bit.open() * mx.when0.open());
|
||||
|
||||
auto fresh = dpf::beavers::sample_fresh<4, u64>(rng);
|
||||
EXPECT_EQ(fresh.subset[(1u << 4) - 2].open(),
|
||||
fresh.in[0].open() * fresh.in[1].open() * fresh.in[2].open()
|
||||
* fresh.in[3].open());
|
||||
}
|
||||
|
||||
TEST(Beaver, DefaultSamplerOpens)
|
||||
{
|
||||
auto t = dpf::beavers::sample_beaver2<u64>();
|
||||
EXPECT_EQ(t.ab.open(), t.a.open() * t.b.open());
|
||||
}
|
||||
|
||||
TEST(BufferedPrg, SeedReplaysLanesInAnyOrder)
|
||||
{
|
||||
using block = dpf::prg::aes128::block_type;
|
||||
block seed = simde_mm_set_epi64x(0x1111, 0x2222);
|
||||
dpf::beavers::oracle<u64> first(seed, 4);
|
||||
dpf::beavers::oracle<u64> second(seed, 4);
|
||||
u64 late = first.blind(1, 10);
|
||||
u64 early = first.blind(0, 0);
|
||||
EXPECT_EQ(second.blind(1, 10), late);
|
||||
EXPECT_EQ(second.blind(0, 0), early);
|
||||
EXPECT_EQ(first.mask(0, 10), second.mask(0, 10));
|
||||
EXPECT_NE(first.blind(0, 0), first.blind(1, 0));
|
||||
|
||||
dpf::randomness::aes_buffered_prg<u64, u64> streamed(seed, 8);
|
||||
u64 s0 = streamed.get<0>();
|
||||
u64 s1 = streamed.get<1>();
|
||||
dpf::randomness::aes_buffered_prg<u64, u64> replay(seed, 8);
|
||||
EXPECT_EQ(replay.at<0>(0), s0);
|
||||
EXPECT_EQ(replay.at<1>(0), s1);
|
||||
EXPECT_EQ(replay.get<0>(), s0);
|
||||
|
||||
dpf::randomness::buffered_prg<dpf::prg::dummy, u64> dummy_stream(seed, 4);
|
||||
u64 d0 = dummy_stream.get<0>();
|
||||
dpf::randomness::buffered_prg<dpf::prg::dummy, u64> dummy_replay(seed, 4);
|
||||
EXPECT_EQ(dummy_replay.at<0>(0), d0);
|
||||
EXPECT_EQ(dummy_replay.at<0>(2), d0);
|
||||
}
|
||||
|
||||
TEST(Beaver, OracleCopiesStayOnOneLanePerBlind)
|
||||
{
|
||||
using block = dpf::prg::aes128::block_type;
|
||||
block seed = simde_mm_set_epi64x(0x9, 0x9);
|
||||
dpf::beavers::oracle<u64> src(seed, 4);
|
||||
dpf::beavers::beaver2<u64> bulk[32];
|
||||
dpf::beavers::fill_beaver2(src, 0, bulk, 32);
|
||||
|
||||
dpf::beavers::oracle<u64> again(seed, 4);
|
||||
auto at31 = dpf::beavers::beaver2_at(again, 31);
|
||||
auto at4 = dpf::beavers::beaver2_at(src, 4);
|
||||
EXPECT_EQ(bulk[31].a, at31.a);
|
||||
EXPECT_EQ(bulk[31].b, at31.b);
|
||||
EXPECT_EQ(bulk[31].ab, at31.ab);
|
||||
EXPECT_EQ(bulk[31].out, at31.out);
|
||||
EXPECT_EQ(bulk[4].a, at4.a);
|
||||
EXPECT_EQ(bulk[4].ab, at4.ab);
|
||||
EXPECT_EQ(bulk[0].ab.open(), bulk[0].a.open() * bulk[0].b.open());
|
||||
EXPECT_EQ(bulk[31].ab.open(), bulk[31].a.open() * bulk[31].b.open());
|
||||
|
||||
dpf::beavers::session<u64> formula;
|
||||
auto x = formula.input();
|
||||
auto y = formula.input();
|
||||
auto z = formula(x * y);
|
||||
auto m = formula.material_at(src, 7);
|
||||
auto one = dpf::beavers::beaver2_at(src, 7);
|
||||
EXPECT_EQ(m.lambda[0], one.a);
|
||||
EXPECT_EQ(m.lambda[1], one.b);
|
||||
EXPECT_EQ(m.lambda[2], one.out);
|
||||
EXPECT_EQ(m.bundles[0].open(), one.ab.open());
|
||||
EXPECT_EQ(m.lambda[0], bulk[7].a);
|
||||
|
||||
formula.sample_from(src, 7);
|
||||
formula.bind(x, u64{6});
|
||||
formula.bind(y, u64{7});
|
||||
formula.evaluate();
|
||||
EXPECT_EQ(formula.open(z), 42u);
|
||||
EXPECT_EQ(formula.lambda(x), one.a);
|
||||
}
|
||||
|
||||
TEST(Beaver, GrottoAppendixEPreprocessing)
|
||||
{
|
||||
dpf::beavers::session<u64> linear;
|
||||
auto x = linear.input();
|
||||
auto sgn = linear.input();
|
||||
auto a0 = linear.input();
|
||||
auto a1 = linear.input();
|
||||
auto lin = linear(sgn * (a1 * x + a0));
|
||||
(void)lin;
|
||||
// Four masks plus four fused products (ePrint 2023/108, Table 3).
|
||||
EXPECT_EQ(linear.preprocessing_count(), 8u);
|
||||
|
||||
dpf::beavers::session<u64> quad;
|
||||
auto x2 = quad.input();
|
||||
auto s2 = quad.input();
|
||||
auto b0 = quad.input();
|
||||
auto b1 = quad.input();
|
||||
auto b2 = quad.input();
|
||||
auto q = quad(s2 * (b2 * pow(x2, 2) + b1 * x2 + b0));
|
||||
(void)q;
|
||||
EXPECT_EQ(quad.preprocessing_count(), 13u);
|
||||
|
||||
dpf::beavers::session<u64> cube;
|
||||
auto x3 = cube.input();
|
||||
auto s3 = cube.input();
|
||||
auto c0 = cube.input();
|
||||
auto c1 = cube.input();
|
||||
auto c2 = cube.input();
|
||||
auto c3 = cube.input();
|
||||
auto y = cube(s3 * (c3 * pow(x3, 3) + c2 * pow(x3, 2) + c1 * x3 + c0));
|
||||
EXPECT_EQ(cube.preprocessing_count(), 18u);
|
||||
|
||||
Counter rng;
|
||||
cube.sample(rng);
|
||||
cube.bind(x3, u64{2}, rng);
|
||||
cube.bind(s3, u64{3}, rng);
|
||||
cube.bind(c0, u64{4}, rng);
|
||||
cube.bind(c1, u64{5}, rng);
|
||||
cube.bind(c2, u64{6}, rng);
|
||||
cube.bind(c3, u64{7}, rng);
|
||||
cube.evaluate();
|
||||
EXPECT_EQ(cube.open(y), 3u * (7u * 8u + 6u * 4u + 5u * 2u + 4u));
|
||||
}
|
||||
|
||||
TEST(Beaver, MultivariatePolynomialsSharePowers)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto z = s.input();
|
||||
auto sgn = s.input();
|
||||
auto p = s(u64{2} + u64{3} * x + u64{4} * y + u64{5} * x * y
|
||||
+ u64{6} * pow(x, 2) + pow(x, 2) * y + monomial(u64{9}, x, y, z));
|
||||
EXPECT_EQ(s.round_of(p), 1);
|
||||
// Fused buckets: fewer shares than one subset product per monomial.
|
||||
EXPECT_EQ(s.monomial_count(), 5u);
|
||||
auto q = s(sgn * (x * y + pow(x, 2)));
|
||||
EXPECT_EQ(s.round_of(q), 1);
|
||||
// Sign crosses are new; λx² and λx λy are not sampled again.
|
||||
EXPECT_EQ(s.monomial_count(), 10u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(x, u64{2}, rng);
|
||||
s.bind(y, u64{3}, rng);
|
||||
s.bind(z, u64{4}, rng);
|
||||
s.bind(sgn, u64{5}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(p),
|
||||
2u + 3u * 2u + 4u * 3u + 5u * 2u * 3u + 6u * 4u + 4u * 3u + 9u * 2u * 3u * 4u);
|
||||
EXPECT_EQ(s.open(q), 5u * (2u * 3u + 4u));
|
||||
}
|
||||
|
||||
TEST(Beaver, PolynomialsSharePowers)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto x = s.input();
|
||||
auto quad = s(u64{1} + u64{2} * x + u64{3} * pow(x, 2));
|
||||
auto cube = s.horner(x, {u64{4}, u64{0}, u64{5}, u64{6}});
|
||||
EXPECT_EQ(s.round_of(quad), 1);
|
||||
EXPECT_EQ(s.round_of(cube), 1);
|
||||
// λx² is shared. The cubic also needs λx³, and one fused bucket.
|
||||
EXPECT_EQ(s.monomial_count(), 3u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(x, u64{3}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(quad), 1u + 2u * 3u + 3u * 9u);
|
||||
EXPECT_EQ(s.open(cube), 4u + 5u * 9u + 6u * 27u);
|
||||
}
|
||||
|
||||
TEST(Beaver, SignMultipliesThePolynomialInOneRound)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto sgn = s.input();
|
||||
auto x = s.input();
|
||||
auto y = s(sgn * (u64{1} + x + pow(x, 2)));
|
||||
auto z = s.horner(sgn, x, {u64{1}, u64{1}, u64{1}});
|
||||
EXPECT_EQ(s.round_of(y), 1);
|
||||
EXPECT_EQ(s.round_of(z), 1);
|
||||
// λx², λsgn λx, λsgn λx². The two polynomials share them.
|
||||
EXPECT_EQ(s.monomial_count(), 3u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(sgn, u64{2}, rng);
|
||||
s.bind(x, u64{3}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(y), 2u * (1u + 3u + 9u));
|
||||
EXPECT_EQ(s.open(z), s.open(y));
|
||||
}
|
||||
|
||||
TEST(Beaver, LikeTermsCollapse)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto p = s(x * y + y * x);
|
||||
auto q = s(u64{5} * pow(x, 2) + u64{3} * x * x);
|
||||
EXPECT_EQ(s.monomial_count(), 2u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(x, u64{4}, rng);
|
||||
s.bind(y, u64{6}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(p), 2u * 4u * 6u);
|
||||
EXPECT_EQ(s.open(q), 8u * 16u);
|
||||
}
|
||||
|
||||
TEST(Beaver, RejectsBadUse)
|
||||
{
|
||||
dpf::beavers::session<u64> a;
|
||||
dpf::beavers::session<u64> b;
|
||||
auto x = a.input();
|
||||
auto y = b.input();
|
||||
EXPECT_THROW((void)[&] { return a.product(x, y); }(), std::invalid_argument);
|
||||
EXPECT_THROW((void)[&] { return x * y; }(), std::invalid_argument);
|
||||
auto bit = a.bit();
|
||||
EXPECT_THROW(a.bind(bit, u64{2}), std::invalid_argument);
|
||||
auto z = a.product(x, x);
|
||||
EXPECT_THROW(a.evaluate(), std::logic_error);
|
||||
a.sample();
|
||||
EXPECT_THROW(a.evaluate(), std::logic_error);
|
||||
EXPECT_THROW((void)[&] { return a.bit_mul(x, x); }(), std::invalid_argument);
|
||||
(void)z;
|
||||
}
|
||||
410
test/tests/bit_array_test.cpp
Normal file
410
test/tests/bit_array_test.cpp
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "dpf/bit_array.hpp"
|
||||
#include "dpf/bitstring.hpp"
|
||||
|
||||
using namespace dpf::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename Array>
|
||||
std::size_t ref_count(const Array &a, std::size_t lo, std::size_t hi)
|
||||
{
|
||||
std::size_t n = 0;
|
||||
for (std::size_t i = lo; i < hi; ++i)
|
||||
n += static_cast<bool>(a[i]) ? 1u : 0u;
|
||||
return n;
|
||||
}
|
||||
|
||||
template <typename Array>
|
||||
int ref_parity(const Array &a, std::size_t lo, std::size_t hi)
|
||||
{
|
||||
int p = 0;
|
||||
for (std::size_t i = lo; i < hi; ++i)
|
||||
p ^= static_cast<bool>(a[i]) ? 1 : 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename Array>
|
||||
bool ref_all(const Array &a, std::size_t lo, std::size_t hi)
|
||||
{
|
||||
for (std::size_t i = lo; i < hi; ++i)
|
||||
if (!static_cast<bool>(a[i])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Array>
|
||||
bool ref_any(const Array &a, std::size_t lo, std::size_t hi)
|
||||
{
|
||||
for (std::size_t i = lo; i < hi; ++i)
|
||||
if (static_cast<bool>(a[i])) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Array>
|
||||
void expect_reductions(Array &a)
|
||||
{
|
||||
const std::size_t n = a.size();
|
||||
EXPECT_EQ(a.count(), ref_count(a, 0, n));
|
||||
EXPECT_EQ(static_cast<int>(a.any()), static_cast<int>(ref_any(a, 0, n)));
|
||||
EXPECT_EQ(static_cast<int>(a.none()), static_cast<int>(!ref_any(a, 0, n)));
|
||||
EXPECT_EQ(static_cast<int>(a.all()), static_cast<int>(ref_all(a, 0, n)));
|
||||
EXPECT_EQ(a.parity(), static_cast<std::size_t>(ref_parity(a, 0, n)));
|
||||
|
||||
const std::size_t cuts[][2] = {
|
||||
{0, 0},
|
||||
{0, n},
|
||||
{0, std::min<std::size_t>(n, 1)},
|
||||
{0, std::min<std::size_t>(n, 3)},
|
||||
{std::min<std::size_t>(n, 2), std::min<std::size_t>(n, 10)},
|
||||
{n > 60 ? n - 60 : 0, n},
|
||||
{n > 70 ? std::size_t{60} : std::size_t{0}, std::min<std::size_t>(n, 70)},
|
||||
{n / 2, std::min(n, n / 2 + 1)},
|
||||
};
|
||||
for (const auto &c : cuts)
|
||||
{
|
||||
if (c[0] > c[1] || c[1] > n) continue;
|
||||
auto first = a.begin() + static_cast<std::ptrdiff_t>(c[0]);
|
||||
auto last = a.begin() + static_cast<std::ptrdiff_t>(c[1]);
|
||||
EXPECT_EQ(a.count(first, last), ref_count(a, c[0], c[1]));
|
||||
EXPECT_EQ(static_cast<int>(a.any(first, last)), static_cast<int>(ref_any(a, c[0], c[1])));
|
||||
EXPECT_EQ(static_cast<int>(a.all(first, last)), static_cast<int>(ref_all(a, c[0], c[1])));
|
||||
EXPECT_EQ(static_cast<int>(a.none(first, last)), static_cast<int>(!ref_any(a, c[0], c[1])));
|
||||
EXPECT_EQ(a.parity(first, last), static_cast<std::size_t>(ref_parity(a, c[0], c[1])));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Array>
|
||||
void exercise(Array a)
|
||||
{
|
||||
const std::size_t n = a.size();
|
||||
a.unset();
|
||||
expect_reductions(a);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
a.set(n / 2, true);
|
||||
if (n > 2) a.set(0, true);
|
||||
expect_reductions(a);
|
||||
}
|
||||
|
||||
a.unset();
|
||||
for (std::size_t i = 0; i < n; ++i) a.set(i, true);
|
||||
expect_reductions(a);
|
||||
EXPECT_EQ(a.count(), n);
|
||||
if (n > 0) EXPECT_TRUE(a.all());
|
||||
|
||||
a.set();
|
||||
expect_reductions(a);
|
||||
EXPECT_EQ(a.count(), n);
|
||||
if (n > 0) EXPECT_TRUE(a.all());
|
||||
EXPECT_EQ(a.parity(), n % 2);
|
||||
|
||||
a.unset();
|
||||
for (std::size_t i = 0; i < n; ++i) a.set(i, (i % 3) != 0);
|
||||
expect_reductions(a);
|
||||
|
||||
if (n > 1)
|
||||
{
|
||||
EXPECT_EQ(a.end() - static_cast<std::ptrdiff_t>(n), a.begin());
|
||||
EXPECT_EQ(a.begin() + static_cast<std::ptrdiff_t>(n), a.end());
|
||||
EXPECT_EQ(5 + a.begin(), a.begin() + 5);
|
||||
auto back = a.begin() + static_cast<std::ptrdiff_t>(std::min<std::size_t>(n, 64));
|
||||
const auto dest = static_cast<std::ptrdiff_t>(std::min<std::size_t>(n, 64)) - 3;
|
||||
if (dest >= 0)
|
||||
{
|
||||
back += -3;
|
||||
EXPECT_EQ(back, a.begin() + dest);
|
||||
EXPECT_EQ(static_cast<bool>(*back), static_cast<bool>(a[static_cast<std::size_t>(dest)]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
constexpr auto kLiteral = 10101001_bitstring;
|
||||
static_assert(kLiteral.size() == 8);
|
||||
static_assert(kLiteral == dpf::bitstring<8>(0b10101001));
|
||||
static_assert(dpf::utils::quotient_ceiling<std::size_t>(0, 64) == 0);
|
||||
static_assert(dpf::utils::quotient_ceiling<std::size_t>(1, 64) == 1);
|
||||
static_assert(dpf::utils::quotient_ceiling<std::size_t>(64, 64) == 1);
|
||||
static_assert(dpf::utils::quotient_ceiling<std::size_t>(65, 64) == 2);
|
||||
|
||||
TEST(BitArray, QuotientCeilingZero)
|
||||
{
|
||||
EXPECT_EQ(dpf::utils::quotient_ceiling<std::size_t>(0, 8), 0u);
|
||||
EXPECT_EQ(dpf::utils::quotient_ceiling<std::size_t>(9, 8), 2u);
|
||||
}
|
||||
|
||||
TEST(BitArray, StaticPayloadIsZero)
|
||||
{
|
||||
dpf::static_bit_array<80> a;
|
||||
EXPECT_EQ(a.data()[0], 0u);
|
||||
EXPECT_EQ(a.data()[1], 0u);
|
||||
EXPECT_EQ(a.count(), 0u);
|
||||
EXPECT_FALSE(a.any());
|
||||
EXPECT_TRUE(a.none());
|
||||
EXPECT_FALSE(a.all());
|
||||
|
||||
dpf::static_bit_array<80> seeded(0x11);
|
||||
EXPECT_EQ(seeded.data()[0], 0x11u);
|
||||
EXPECT_EQ(seeded.data()[1], 0u);
|
||||
EXPECT_EQ(seeded.count(), 2u);
|
||||
|
||||
dpf::static_bit_array<80> wide_val(0x1FFFF);
|
||||
EXPECT_EQ(wide_val.data()[0], 0x1FFFFu);
|
||||
EXPECT_EQ(wide_val.data()[1], 0u);
|
||||
EXPECT_EQ(wide_val.count(), 17u);
|
||||
|
||||
dpf::static_bit_array<4> narrow(0xFF);
|
||||
EXPECT_EQ(narrow.count(), 4u);
|
||||
EXPECT_TRUE(narrow.all());
|
||||
}
|
||||
|
||||
TEST(BitArray, DynamicPayloadIsZeroAndEmptyIsEmpty)
|
||||
{
|
||||
dpf::dynamic_bit_array<> a(130);
|
||||
ASSERT_NE(a.data(), nullptr);
|
||||
for (std::size_t i = 0; i < a.data_length(); ++i)
|
||||
EXPECT_EQ(a.data(i), 0u);
|
||||
|
||||
dpf::dynamic_bit_array<> empty(0);
|
||||
EXPECT_EQ(empty.size(), 0u);
|
||||
EXPECT_EQ(empty.data_length(), 0u);
|
||||
EXPECT_TRUE(empty.all());
|
||||
EXPECT_FALSE(empty.any());
|
||||
EXPECT_EQ(empty.count(), 0u);
|
||||
EXPECT_EQ(empty.parity(), 0u);
|
||||
EXPECT_EQ(empty.begin(), empty.end());
|
||||
}
|
||||
|
||||
TEST(BitArray, DynamicCopyAndMove)
|
||||
{
|
||||
dpf::dynamic_bit_array<> a(70);
|
||||
a.set(3, true);
|
||||
a.set(69, true);
|
||||
|
||||
dpf::dynamic_bit_array<> b = a;
|
||||
b.set(3, false);
|
||||
EXPECT_TRUE(static_cast<bool>(a[3]));
|
||||
EXPECT_FALSE(static_cast<bool>(b[3]));
|
||||
EXPECT_TRUE(static_cast<bool>(b[69]));
|
||||
|
||||
dpf::dynamic_bit_array<> c(8);
|
||||
c = a;
|
||||
EXPECT_TRUE(static_cast<bool>(c[69]));
|
||||
EXPECT_EQ(c.size(), 70u);
|
||||
|
||||
auto moved = std::move(a);
|
||||
EXPECT_EQ(a.size(), 0u);
|
||||
EXPECT_EQ(a.data(), nullptr);
|
||||
EXPECT_TRUE(static_cast<bool>(moved[3]));
|
||||
EXPECT_TRUE(static_cast<bool>(moved[69]));
|
||||
}
|
||||
|
||||
TEST(BitArray, TailBitsAreIgnored)
|
||||
{
|
||||
exercise(dpf::dynamic_bit_array<>(1));
|
||||
exercise(dpf::dynamic_bit_array<>(7));
|
||||
exercise(dpf::dynamic_bit_array<>(8));
|
||||
exercise(dpf::dynamic_bit_array<>(9));
|
||||
exercise(dpf::dynamic_bit_array<>(63));
|
||||
exercise(dpf::dynamic_bit_array<>(64));
|
||||
exercise(dpf::dynamic_bit_array<>(65));
|
||||
exercise(dpf::dynamic_bit_array<>(130));
|
||||
exercise(dpf::static_bit_array<1>{});
|
||||
exercise(dpf::static_bit_array<10>{});
|
||||
exercise(dpf::static_bit_array<64>{});
|
||||
exercise(dpf::static_bit_array<70>{});
|
||||
exercise(dpf::static_bit_array<40, std::uint8_t>{});
|
||||
exercise(dpf::static_bit_array<400, std::uint8_t>{});
|
||||
exercise(dpf::static_bit_array<20, std::uint16_t>{});
|
||||
exercise(dpf::bitstring<1>{});
|
||||
exercise(dpf::bitstring<9>{});
|
||||
exercise(dpf::bitstring<10>{});
|
||||
exercise(dpf::bitstring<64>{});
|
||||
exercise(dpf::bitstring<65>{});
|
||||
exercise(dpf::bitstring<70, std::uint8_t>{});
|
||||
}
|
||||
|
||||
TEST(BitArray, SameWordRangeDoesNotRunOff)
|
||||
{
|
||||
dpf::dynamic_bit_array<> a(32);
|
||||
a.unset();
|
||||
a.set(0, true);
|
||||
a.set(10, true);
|
||||
EXPECT_FALSE(a.any(a.begin() + 1, a.begin() + 10));
|
||||
EXPECT_TRUE(a.any(a.begin(), a.begin() + 1));
|
||||
EXPECT_EQ(a.count(a.begin(), a.begin() + 11), 2u);
|
||||
EXPECT_FALSE(a.all(a.begin(), a.begin() + 11));
|
||||
EXPECT_TRUE(a.all(a.begin() + 3, a.begin() + 3));
|
||||
EXPECT_FALSE(a.any(a.begin() + 3, a.begin() + 3));
|
||||
EXPECT_EQ(a.count(a.begin() + 3, a.begin() + 3), 0u);
|
||||
EXPECT_EQ(a.parity(a.begin() + 3, a.begin() + 3), 0u);
|
||||
|
||||
a.set();
|
||||
EXPECT_TRUE(a.all(a.begin() + 2, a.begin() + 9));
|
||||
EXPECT_EQ(a.count(a.begin() + 2, a.begin() + 9), 7u);
|
||||
EXPECT_EQ(a.parity(a.begin() + 2, a.begin() + 9), 1u);
|
||||
}
|
||||
|
||||
TEST(BitArray, CrossWordRangeAndFullBitstring)
|
||||
{
|
||||
dpf::dynamic_bit_array<> a(130);
|
||||
a.unset();
|
||||
a.set(63, true);
|
||||
a.set(64, true);
|
||||
a.set(100, true);
|
||||
EXPECT_EQ(a.count(a.begin() + 60, a.begin() + 70), 2u);
|
||||
EXPECT_TRUE(a.any(a.begin() + 60, a.begin() + 70));
|
||||
EXPECT_FALSE(a.all(a.begin() + 60, a.begin() + 70));
|
||||
EXPECT_EQ(a.parity(a.begin() + 60, a.begin() + 70), 0u);
|
||||
|
||||
dpf::bitstring<64> aligned;
|
||||
aligned.set(1, true);
|
||||
EXPECT_TRUE(aligned.any(aligned.begin(), aligned.end()));
|
||||
EXPECT_EQ(aligned.count(aligned.begin(), aligned.end()), 1u);
|
||||
EXPECT_FALSE(aligned.all(aligned.begin(), aligned.end()));
|
||||
aligned.set();
|
||||
EXPECT_TRUE(aligned.all(aligned.begin(), aligned.end()));
|
||||
EXPECT_EQ(aligned.count(aligned.begin(), aligned.end()), 64u);
|
||||
|
||||
dpf::bitstring<128> wide;
|
||||
wide.set();
|
||||
EXPECT_TRUE(wide.all(wide.begin(), wide.end()));
|
||||
EXPECT_EQ(wide.count(wide.begin(), wide.end()), 128u);
|
||||
EXPECT_EQ(wide.parity(wide.begin(), wide.end()), 0u);
|
||||
}
|
||||
|
||||
TEST(BitArray, NarrowWordCountCompilesAndFits)
|
||||
{
|
||||
dpf::static_bit_array<400, std::uint8_t> wide;
|
||||
wide.set();
|
||||
EXPECT_EQ(wide.count(), 400u);
|
||||
EXPECT_TRUE(wide.all());
|
||||
EXPECT_EQ(wide.parity(), 0u);
|
||||
|
||||
dpf::bitstring<10> partial;
|
||||
partial.set(0, true);
|
||||
partial.set(3, true);
|
||||
EXPECT_EQ(partial.count(partial.begin(), partial.begin() + 4), 2u);
|
||||
EXPECT_EQ(partial.count(partial.begin(), partial.end()), 2u);
|
||||
partial.set();
|
||||
EXPECT_EQ(partial.count(), 10u);
|
||||
EXPECT_EQ(partial.count(partial.begin(), partial.end()), 10u);
|
||||
}
|
||||
|
||||
TEST(BitString, SetMatchesFlipAndIgnoresPadding)
|
||||
{
|
||||
dpf::bitstring<65> set_bits;
|
||||
set_bits.set();
|
||||
dpf::bitstring<65> flipped = ~dpf::bitstring<65>{};
|
||||
EXPECT_EQ(set_bits, flipped);
|
||||
EXPECT_EQ(set_bits.count(), 65u);
|
||||
EXPECT_EQ(flipped.count(), 65u);
|
||||
EXPECT_EQ(set_bits.parity(), 1u);
|
||||
|
||||
dpf::bitstring<10> dirty;
|
||||
using word = std::remove_reference_t<decltype(dirty.data(0))>;
|
||||
dirty.data(0) = static_cast<word>(word{1} << 10);
|
||||
dpf::bitstring<10> clean;
|
||||
EXPECT_EQ(dirty, clean);
|
||||
EXPECT_FALSE(dirty.any());
|
||||
EXPECT_TRUE(dirty.none());
|
||||
EXPECT_EQ(dirty.count(), 0u);
|
||||
EXPECT_FALSE(dirty.all());
|
||||
|
||||
const auto clz = dpf::utils::countl_zero_symmetric_difference<dpf::bitstring<10>>{};
|
||||
EXPECT_EQ(clz(dirty, clean), 10u);
|
||||
dpf::bitstring<10> ones = ~dpf::bitstring<10>{};
|
||||
dpf::bitstring<10> also_ones;
|
||||
also_ones.set();
|
||||
EXPECT_EQ(clz(also_ones, ones), 10u);
|
||||
|
||||
dpf::bitstring<1> one_set;
|
||||
one_set.set();
|
||||
EXPECT_EQ(one_set.count(), 1u);
|
||||
EXPECT_EQ(dpf::utils::countl_zero_symmetric_difference<dpf::bitstring<1>>{}(
|
||||
one_set, ~dpf::bitstring<1>{}), 1u);
|
||||
}
|
||||
|
||||
TEST(BitString, OrderingXorAndIncrement)
|
||||
{
|
||||
dpf::bitstring<12> lo(1);
|
||||
dpf::bitstring<12> hi;
|
||||
hi.set(11, true);
|
||||
EXPECT_LT(lo, hi);
|
||||
EXPECT_GT(hi, lo);
|
||||
EXPECT_NE(lo, hi);
|
||||
EXPECT_EQ(lo + dpf::bitstring<12>(1), dpf::bitstring<12>{});
|
||||
auto inc = lo;
|
||||
++inc;
|
||||
EXPECT_EQ(inc, dpf::bitstring<12>(2));
|
||||
|
||||
dpf::bitstring<80> wrapped = ~dpf::bitstring<80>{};
|
||||
++wrapped;
|
||||
EXPECT_EQ(wrapped, dpf::bitstring<80>{});
|
||||
--wrapped;
|
||||
EXPECT_EQ(wrapped, ~dpf::bitstring<80>{});
|
||||
}
|
||||
|
||||
TEST(BitString, MaskShiftPastZeroDoesNotIndex)
|
||||
{
|
||||
dpf::bitstring<8> b(1);
|
||||
auto mask = dpf::utils::msb_of_v<dpf::bitstring<8>>;
|
||||
mask >>= 8;
|
||||
EXPECT_FALSE(static_cast<bool>(mask));
|
||||
EXPECT_FALSE(mask & b);
|
||||
EXPECT_FALSE(b & mask);
|
||||
}
|
||||
|
||||
TEST(BitString, ModPow2WideShiftIsDefined)
|
||||
{
|
||||
dpf::bitstring<80> b;
|
||||
b.set(3, true);
|
||||
b.set(70, true);
|
||||
const auto mod = dpf::utils::mod_pow_2<dpf::bitstring<80>>{};
|
||||
EXPECT_EQ(mod(b, 4), 8u);
|
||||
EXPECT_EQ(mod(b, 70), 8u);
|
||||
EXPECT_EQ(mod(b, 0), 0u);
|
||||
}
|
||||
|
||||
TEST(BitArray, IteratorArithmeticAndAlgorithms)
|
||||
{
|
||||
using iter = dpf::dynamic_bit_array<>::iterator;
|
||||
EXPECT_TRUE(std::is_default_constructible_v<iter>);
|
||||
iter singular_a, singular_b;
|
||||
EXPECT_EQ(singular_a, singular_b);
|
||||
|
||||
dpf::static_bit_array<40, std::uint8_t> narrow;
|
||||
narrow.unset();
|
||||
narrow.set(7, true);
|
||||
auto it = narrow.begin() + 8;
|
||||
it += -1;
|
||||
EXPECT_EQ(it, narrow.begin() + 7);
|
||||
EXPECT_TRUE(static_cast<bool>(*it));
|
||||
EXPECT_EQ(narrow.end() - static_cast<std::ptrdiff_t>(narrow.size()), narrow.begin());
|
||||
|
||||
dpf::static_bit_array<16> bits;
|
||||
bits.unset();
|
||||
for (std::size_t i = 0; i < 16; ++i) bits.set(i, i < 4);
|
||||
using std::swap;
|
||||
swap(bits[0], bits[15]);
|
||||
EXPECT_FALSE(static_cast<bool>(bits[0]));
|
||||
EXPECT_TRUE(static_cast<bool>(bits[15]));
|
||||
std::reverse(bits.begin(), bits.end());
|
||||
EXPECT_TRUE(static_cast<bool>(bits[0]));
|
||||
EXPECT_FALSE(static_cast<bool>(bits[15]));
|
||||
}
|
||||
|
||||
TEST(BitString, LiteralMatchesIntegerCtor)
|
||||
{
|
||||
EXPECT_EQ(kLiteral, dpf::bitstring<8>(0b10101001));
|
||||
EXPECT_EQ(kLiteral.to_string(), "10101001");
|
||||
}
|
||||
720
test/tests/constant_lut_test.cpp
Normal file
720
test/tests/constant_lut_test.cpp
Normal file
|
|
@ -0,0 +1,720 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "grotto/constant_lut.hpp"
|
||||
#include "grotto/prefix_parity.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using grotto::exact_constant;
|
||||
using u128 = unsigned __int128;
|
||||
|
||||
const exact_constant kAll[] = {
|
||||
exact_constant::signum,
|
||||
exact_constant::positive,
|
||||
exact_constant::negative,
|
||||
exact_constant::nonneg,
|
||||
exact_constant::nonpos,
|
||||
exact_constant::zero,
|
||||
exact_constant::nonzero,
|
||||
exact_constant::ilogb,
|
||||
exact_constant::ceil_ilogb,
|
||||
exact_constant::ilog10,
|
||||
exact_constant::clz,
|
||||
exact_constant::clrsb,
|
||||
};
|
||||
|
||||
const char * name_of(exact_constant which)
|
||||
{
|
||||
switch (which)
|
||||
{
|
||||
case exact_constant::signum: return "signum";
|
||||
case exact_constant::positive: return "positive";
|
||||
case exact_constant::negative: return "negative";
|
||||
case exact_constant::nonneg: return "nonneg";
|
||||
case exact_constant::nonpos: return "nonpos";
|
||||
case exact_constant::zero: return "zero";
|
||||
case exact_constant::nonzero: return "nonzero";
|
||||
case exact_constant::ilogb: return "ilogb";
|
||||
case exact_constant::ceil_ilogb: return "ceil_ilogb";
|
||||
case exact_constant::ilog10: return "ilog10";
|
||||
case exact_constant::clz: return "clz";
|
||||
case exact_constant::clrsb: return "clrsb";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
unsigned __int128 magnitude(std::int64_t raw)
|
||||
{
|
||||
if (raw >= 0)
|
||||
return static_cast<unsigned __int128>(raw);
|
||||
if (raw == std::numeric_limits<std::int64_t>::min())
|
||||
return u128{1} << 63;
|
||||
return static_cast<unsigned __int128>(-raw);
|
||||
}
|
||||
|
||||
int shift_log2(unsigned __int128 mag)
|
||||
{
|
||||
int lg = 0;
|
||||
while (mag > 1)
|
||||
{
|
||||
mag >>= 1;
|
||||
++lg;
|
||||
}
|
||||
return lg;
|
||||
}
|
||||
|
||||
int shift_clz64(std::uint64_t t)
|
||||
{
|
||||
int n = 0;
|
||||
if (t == 0)
|
||||
return 64;
|
||||
while ((t & (std::uint64_t{1} << 63)) == 0)
|
||||
{
|
||||
t <<= 1;
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
bool ge_pow10(unsigned __int128 mag, int k, unsigned fractional_bits)
|
||||
{
|
||||
if (k >= 0)
|
||||
{
|
||||
unsigned __int128 thresh = 1;
|
||||
for (int i = 0; i < k; ++i)
|
||||
{
|
||||
if (thresh > (~u128{0}) / 10)
|
||||
return false;
|
||||
thresh *= 10;
|
||||
}
|
||||
if (fractional_bits >= 128
|
||||
|| thresh > (~u128{0} >> fractional_bits))
|
||||
return false;
|
||||
return mag >= (thresh << fractional_bits);
|
||||
}
|
||||
unsigned __int128 scaled = mag;
|
||||
for (int i = 0; i < -k; ++i)
|
||||
{
|
||||
if (scaled > (~u128{0}) / 10)
|
||||
return true;
|
||||
scaled *= 10;
|
||||
}
|
||||
return fractional_bits < 128 && scaled >= (u128{1} << fractional_bits);
|
||||
}
|
||||
|
||||
std::int64_t toward_zero(std::int64_t raw, unsigned fractional_bits)
|
||||
{
|
||||
const unsigned __int128 mag = magnitude(raw);
|
||||
const unsigned __int128 q = mag >> fractional_bits;
|
||||
if (raw >= 0)
|
||||
return static_cast<std::int64_t>(q);
|
||||
if (q > static_cast<unsigned __int128>(std::numeric_limits<std::int64_t>::max()))
|
||||
return std::numeric_limits<std::int64_t>::min();
|
||||
return -static_cast<std::int64_t>(q);
|
||||
}
|
||||
|
||||
// Independent of grotto::detail: shift loops and the xor form of clrsb,
|
||||
// not the builtins the LUT builder calls.
|
||||
std::int64_t reference(exact_constant which, std::int64_t raw, unsigned fractional_bits)
|
||||
{
|
||||
const unsigned __int128 mag = magnitude(raw);
|
||||
switch (which)
|
||||
{
|
||||
case exact_constant::signum:
|
||||
return raw < 0 ? -1 : (raw > 0 ? 1 : 0);
|
||||
case exact_constant::positive:
|
||||
return raw > 0;
|
||||
case exact_constant::negative:
|
||||
return raw < 0;
|
||||
case exact_constant::nonneg:
|
||||
return raw >= 0;
|
||||
case exact_constant::nonpos:
|
||||
return raw <= 0;
|
||||
case exact_constant::zero:
|
||||
return raw == 0;
|
||||
case exact_constant::nonzero:
|
||||
return raw != 0;
|
||||
case exact_constant::ilogb:
|
||||
if (mag == 0)
|
||||
return -64;
|
||||
if (fractional_bits >= 64
|
||||
&& mag <= (u128{1} << (fractional_bits - 64)))
|
||||
return -64;
|
||||
return shift_log2(mag) - static_cast<std::int64_t>(fractional_bits);
|
||||
case exact_constant::ceil_ilogb:
|
||||
if (mag == 0)
|
||||
return -64;
|
||||
if (fractional_bits >= 64
|
||||
&& mag <= (u128{1} << (fractional_bits - 64)))
|
||||
return -64;
|
||||
{
|
||||
const auto floor_exp = shift_log2(mag) - static_cast<std::int64_t>(fractional_bits);
|
||||
const bool power = (mag & (mag - 1)) == 0;
|
||||
return power ? floor_exp : floor_exp + 1;
|
||||
}
|
||||
case exact_constant::ilog10:
|
||||
if (mag == 0 || !ge_pow10(mag, -19, fractional_bits))
|
||||
return -19;
|
||||
{
|
||||
int k = -19;
|
||||
while (k < 40 && ge_pow10(mag, k + 1, fractional_bits))
|
||||
++k;
|
||||
return k;
|
||||
}
|
||||
case exact_constant::clz:
|
||||
if (raw < 0)
|
||||
return 0;
|
||||
if (fractional_bits >= 128 || mag < (u128{1} << fractional_bits))
|
||||
return 64;
|
||||
return shift_clz64(static_cast<std::uint64_t>(mag >> fractional_bits));
|
||||
case exact_constant::clrsb:
|
||||
{
|
||||
const std::int64_t trunc = toward_zero(raw, fractional_bits);
|
||||
const std::uint64_t u = static_cast<std::uint64_t>(trunc);
|
||||
const std::uint64_t y = u ^ static_cast<std::uint64_t>(trunc >> 1);
|
||||
if (y == 0)
|
||||
return 63;
|
||||
return shift_clz64(y) - 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Raw>
|
||||
void expect_partition(const grotto::constant_lut<Raw> & lut)
|
||||
{
|
||||
using lim = std::numeric_limits<Raw>;
|
||||
ASSERT_FALSE(lut.bounds.empty());
|
||||
ASSERT_EQ(lut.bounds.size(), lut.values.size());
|
||||
EXPECT_EQ(lut.bounds.front(), lim::min());
|
||||
for (std::size_t i = 1; i < lut.bounds.size(); ++i)
|
||||
{
|
||||
EXPECT_LT(lut.bounds[i - 1], lut.bounds[i]);
|
||||
EXPECT_NE(lut.values[i - 1], lut.values[i]);
|
||||
EXPECT_EQ(lut(static_cast<Raw>(lut.bounds[i] - 1)), lut.values[i - 1]);
|
||||
}
|
||||
EXPECT_EQ(lut(lim::max()), lut.values.back());
|
||||
for (std::size_t i = 0; i < lut.bounds.size(); ++i)
|
||||
EXPECT_EQ(lut(lut.bounds[i]), lut.values[i]);
|
||||
}
|
||||
|
||||
template <typename Raw, std::size_t N>
|
||||
bool segment_product_matches(const grotto::constant_lut<Raw> & lut, Raw alpha)
|
||||
{
|
||||
std::array<Raw, N> ends{};
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
ends[i] = lut.bounds[i];
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::bit::one);
|
||||
const auto s0 = grotto::segment_parities(k0, ends);
|
||||
const auto s1 = grotto::segment_parities(k1, ends);
|
||||
__int128 a0 = 0;
|
||||
__int128 a1 = 0;
|
||||
__int128 u0 = 0;
|
||||
__int128 u1 = 0;
|
||||
int hot = 0;
|
||||
int hot_at = -1;
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
const int b0 = s0[i] ? 1 : 0;
|
||||
const int b1 = s1[i] ? 1 : 0;
|
||||
a0 += __int128(lut.values[i]) * b0;
|
||||
a1 += __int128(lut.values[i]) * b1;
|
||||
u0 += b0;
|
||||
u1 += b1;
|
||||
if ((b0 ^ b1) != 0)
|
||||
{
|
||||
++hot;
|
||||
hot_at = static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
if (hot != 1)
|
||||
return false;
|
||||
const std::int64_t opened = static_cast<std::int64_t>((u0 - u1) * (a0 - a1));
|
||||
return opened == lut.values[static_cast<std::size_t>(hot_at)]
|
||||
&& opened == lut(alpha);
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
bool dispatch_segments(const grotto::constant_lut<std::int8_t> & lut, std::int8_t alpha)
|
||||
{
|
||||
if (lut.bounds.size() == N)
|
||||
return segment_product_matches<std::int8_t, N>(lut, alpha);
|
||||
if constexpr (N > 1)
|
||||
return dispatch_segments<N - 1>(lut, alpha);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ConstantLut, RejectsFractionalBitsPastTheRawWidth)
|
||||
{
|
||||
EXPECT_THROW(grotto::make_exact_constant_lut<std::int8_t>(exact_constant::signum, 9),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(grotto::make_exact_constant_lut<std::int64_t>(exact_constant::clz, 65),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ConstantLut, PaperPartCountsOnInt64With16FractionalBits)
|
||||
{
|
||||
// Appendix D, 64-bit fixed point, 16 fractional bits.
|
||||
// `zero`, `nonzero`, and `ilog10` are counted after the two end pieces
|
||||
// join across the wrap (they hold the same constant). `clrsb` is the
|
||||
// linear count the generator emits; joining its equal ends would make 94.
|
||||
struct row
|
||||
{
|
||||
exact_constant which;
|
||||
std::size_t linear;
|
||||
std::size_t wrapped;
|
||||
};
|
||||
const row rows[] = {
|
||||
{exact_constant::signum, 3, 3},
|
||||
{exact_constant::positive, 2, 2},
|
||||
{exact_constant::negative, 2, 2},
|
||||
{exact_constant::nonneg, 2, 2},
|
||||
{exact_constant::nonpos, 2, 2},
|
||||
{exact_constant::zero, 3, 2},
|
||||
{exact_constant::nonzero, 3, 2},
|
||||
{exact_constant::ilogb, 128, 128},
|
||||
{exact_constant::ilog10, 41, 40},
|
||||
{exact_constant::clz, 49, 49},
|
||||
{exact_constant::clrsb, 95, 94},
|
||||
};
|
||||
for (const row & r : rows)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int64_t>(r.which, 16);
|
||||
expect_partition(lut);
|
||||
EXPECT_EQ(lut.linear_parts(), r.linear) << name_of(r.which);
|
||||
EXPECT_EQ(lut.wrapped_parts(), r.wrapped) << name_of(r.which);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantLut, AnchorsMatchTheDefinitions)
|
||||
{
|
||||
const auto sgn = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::signum, 16);
|
||||
EXPECT_EQ(sgn(0), 0);
|
||||
EXPECT_EQ(sgn(-1), -1);
|
||||
EXPECT_EQ(sgn(1), 1);
|
||||
EXPECT_EQ(sgn(std::numeric_limits<std::int64_t>::min()), -1);
|
||||
EXPECT_EQ(sgn(std::numeric_limits<std::int64_t>::max()), 1);
|
||||
|
||||
const auto pos = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::positive, 0);
|
||||
const auto neg = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::negative, 0);
|
||||
const auto nn = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::nonneg, 0);
|
||||
const auto np = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::nonpos, 0);
|
||||
const auto z = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::zero, 0);
|
||||
const auto nz = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::nonzero, 0);
|
||||
EXPECT_EQ(pos(0), 0);
|
||||
EXPECT_EQ(pos(1), 1);
|
||||
EXPECT_EQ(pos(-1), 0);
|
||||
EXPECT_EQ(neg(0), 0);
|
||||
EXPECT_EQ(neg(-1), 1);
|
||||
EXPECT_EQ(nn(0), 1);
|
||||
EXPECT_EQ(nn(-1), 0);
|
||||
EXPECT_EQ(np(0), 1);
|
||||
EXPECT_EQ(np(1), 0);
|
||||
EXPECT_EQ(z(0), 1);
|
||||
EXPECT_EQ(z(1), 0);
|
||||
EXPECT_EQ(z(-1), 0);
|
||||
EXPECT_EQ(nz(0), 0);
|
||||
EXPECT_EQ(nz(1), 1);
|
||||
|
||||
const auto ilogb = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::ilogb, 16);
|
||||
EXPECT_EQ(ilogb(0), -64);
|
||||
EXPECT_EQ(ilogb(1), -16);
|
||||
EXPECT_EQ(ilogb(-1), -16);
|
||||
EXPECT_EQ(ilogb(65536), 0);
|
||||
EXPECT_EQ(ilogb(-65536), 0);
|
||||
EXPECT_EQ(ilogb(std::numeric_limits<std::int64_t>::min()), 47);
|
||||
|
||||
const auto ilog10 = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::ilog10, 16);
|
||||
EXPECT_EQ(ilog10(0), -19);
|
||||
EXPECT_EQ(ilog10(1), -5);
|
||||
EXPECT_EQ(ilog10(-1), -5);
|
||||
EXPECT_EQ(ilog10(65536), 0);
|
||||
EXPECT_EQ(ilog10(655360), 1);
|
||||
|
||||
const auto clz = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::clz, 16);
|
||||
EXPECT_EQ(clz(0), 64);
|
||||
EXPECT_EQ(clz(1), 64);
|
||||
EXPECT_EQ(clz(65535), 64);
|
||||
EXPECT_EQ(clz(65536), 63);
|
||||
EXPECT_EQ(clz(131072), 62);
|
||||
EXPECT_EQ(clz(-1), 0);
|
||||
EXPECT_EQ(clz(std::int64_t{1} << 62), 17);
|
||||
|
||||
const auto clrsb = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::clrsb, 16);
|
||||
EXPECT_EQ(clrsb(0), 63);
|
||||
EXPECT_EQ(clrsb(65536), 62);
|
||||
EXPECT_EQ(clrsb(-65536), 63);
|
||||
EXPECT_EQ(clrsb(std::numeric_limits<std::int64_t>::min()), 16);
|
||||
}
|
||||
|
||||
TEST(ConstantLut, EveryInt8AndInt16Point)
|
||||
{
|
||||
const unsigned widths_f_8[] = {0, 1, 4, 7, 8};
|
||||
for (unsigned fractional_bits : widths_f_8)
|
||||
{
|
||||
for (exact_constant which : kAll)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int8_t>(which, fractional_bits);
|
||||
expect_partition(lut);
|
||||
for (int raw = -128; raw <= 127; ++raw)
|
||||
{
|
||||
const auto r = static_cast<std::int8_t>(raw);
|
||||
EXPECT_EQ(lut(r), reference(which, r, fractional_bits))
|
||||
<< name_of(which) << " F=" << fractional_bits << " raw=" << raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned widths_f_16[] = {0, 1, 4, 8, 12, 15, 16};
|
||||
for (unsigned fractional_bits : widths_f_16)
|
||||
{
|
||||
for (exact_constant which : kAll)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int16_t>(which, fractional_bits);
|
||||
expect_partition(lut);
|
||||
for (int raw = -32768; raw <= 32767; ++raw)
|
||||
{
|
||||
const auto r = static_cast<std::int16_t>(raw);
|
||||
EXPECT_EQ(lut(r), reference(which, r, fractional_bits))
|
||||
<< name_of(which) << " F=" << fractional_bits << " raw=" << raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantLut, Int32AndInt64BoundariesAndSamples)
|
||||
{
|
||||
const unsigned widths_f_32[] = {0, 1, 8, 16, 31, 32};
|
||||
const unsigned widths_f_64[] = {0, 1, 4, 8, 12, 16, 20, 32, 48, 63, 64};
|
||||
std::mt19937 rng(0x108u);
|
||||
for (exact_constant which : kAll)
|
||||
{
|
||||
for (unsigned fractional_bits : widths_f_32)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int32_t>(which, fractional_bits);
|
||||
expect_partition(lut);
|
||||
for (std::int32_t raw : lut.bounds)
|
||||
EXPECT_EQ(lut(raw), reference(which, raw, fractional_bits));
|
||||
EXPECT_EQ(lut(0), reference(which, 0, fractional_bits));
|
||||
EXPECT_EQ(lut(-1), reference(which, -1, fractional_bits));
|
||||
EXPECT_EQ(lut(1), reference(which, 1, fractional_bits));
|
||||
EXPECT_EQ(lut(std::numeric_limits<std::int32_t>::min()),
|
||||
reference(which, std::numeric_limits<std::int32_t>::min(), fractional_bits));
|
||||
EXPECT_EQ(lut(std::numeric_limits<std::int32_t>::max()),
|
||||
reference(which, std::numeric_limits<std::int32_t>::max(), fractional_bits));
|
||||
std::uniform_int_distribution<std::int32_t> dist;
|
||||
for (int n = 0; n < 256; ++n)
|
||||
{
|
||||
const std::int32_t raw = dist(rng);
|
||||
EXPECT_EQ(lut(raw), reference(which, raw, fractional_bits))
|
||||
<< name_of(which) << " F=" << fractional_bits;
|
||||
}
|
||||
}
|
||||
for (unsigned fractional_bits : widths_f_64)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int64_t>(which, fractional_bits);
|
||||
expect_partition(lut);
|
||||
for (std::size_t i = 0; i < lut.bounds.size(); ++i)
|
||||
{
|
||||
const std::int64_t raw = lut.bounds[i];
|
||||
EXPECT_EQ(lut(raw), reference(which, raw, fractional_bits))
|
||||
<< name_of(which) << " F=" << fractional_bits << " bound " << i;
|
||||
if (i + 1 < lut.bounds.size())
|
||||
{
|
||||
const std::int64_t before = static_cast<std::int64_t>(lut.bounds[i + 1] - 1);
|
||||
EXPECT_EQ(lut(before), reference(which, before, fractional_bits));
|
||||
}
|
||||
}
|
||||
std::uniform_int_distribution<std::int64_t> dist;
|
||||
for (int n = 0; n < 128; ++n)
|
||||
{
|
||||
const std::int64_t raw = dist(rng);
|
||||
EXPECT_EQ(lut(raw), reference(which, raw, fractional_bits))
|
||||
<< name_of(which) << " F=" << fractional_bits << " raw=" << raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantLut, LibmAgreesOnPowersOfTwo)
|
||||
{
|
||||
for (unsigned fractional_bits : {0u, 4u, 8u, 12u, 16u, 20u})
|
||||
{
|
||||
const auto ilogb = grotto::make_exact_constant_lut<std::int64_t>(
|
||||
exact_constant::ilogb, fractional_bits);
|
||||
const auto ilog10 = grotto::make_exact_constant_lut<std::int64_t>(
|
||||
exact_constant::ilog10, fractional_bits);
|
||||
for (int k = 0; k <= 62; ++k)
|
||||
{
|
||||
const std::int64_t raw = std::int64_t{1} << k;
|
||||
const double x = std::ldexp(static_cast<double>(raw), -static_cast<int>(fractional_bits));
|
||||
if (x == 0.0 || !std::isfinite(x))
|
||||
continue;
|
||||
EXPECT_EQ(ilogb(raw), std::ilogb(x)) << "F=" << fractional_bits << " k=" << k;
|
||||
EXPECT_EQ(ilogb(-raw), std::ilogb(-x)) << "F=" << fractional_bits << " k=" << k;
|
||||
const int from_log10 = static_cast<int>(std::floor(std::log10(std::fabs(x))));
|
||||
EXPECT_EQ(ilog10(raw), from_log10) << "F=" << fractional_bits << " k=" << k;
|
||||
EXPECT_EQ(ilog10(-raw), from_log10) << "F=" << fractional_bits << " k=" << k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantLut, PartCountsScaleWithTheDomain)
|
||||
{
|
||||
// clz pieces: one negative piece, the [0, 1) piece, then one piece per
|
||||
// power of two that still fits. For a 64-bit word and F fractional bits
|
||||
// with F <= 62 that is 63 - F + 2.
|
||||
for (unsigned fractional_bits : {0u, 4u, 8u, 16u, 20u, 32u})
|
||||
{
|
||||
const auto clz = grotto::make_exact_constant_lut<std::int64_t>(
|
||||
exact_constant::clz, fractional_bits);
|
||||
EXPECT_EQ(clz.linear_parts(), 63u - fractional_bits + 2u) << fractional_bits;
|
||||
}
|
||||
// No positive power of two fits once every value is strictly inside (-1, 1).
|
||||
EXPECT_EQ(grotto::make_exact_constant_lut<std::int64_t>(exact_constant::clz, 63).linear_parts(), 2u);
|
||||
EXPECT_EQ(grotto::make_exact_constant_lut<std::int64_t>(exact_constant::clz, 64).linear_parts(), 2u);
|
||||
|
||||
// ilogb splits at every raw power of two, on both sides, plus zero: 128
|
||||
// pieces for every fractional width that still sees the whole int64 word.
|
||||
for (unsigned fractional_bits : {0u, 4u, 8u, 12u, 16u, 20u, 32u, 48u, 63u})
|
||||
{
|
||||
EXPECT_EQ(grotto::make_exact_constant_lut<std::int64_t>(
|
||||
exact_constant::ilogb, fractional_bits).linear_parts(), 128u)
|
||||
<< fractional_bits;
|
||||
}
|
||||
|
||||
// Sign tests do not depend on the fractional width.
|
||||
for (unsigned fractional_bits : {0u, 7u, 15u, 16u})
|
||||
{
|
||||
EXPECT_EQ(grotto::make_exact_constant_lut<std::int16_t>(
|
||||
exact_constant::signum, fractional_bits).linear_parts(), 3u);
|
||||
EXPECT_EQ(grotto::make_exact_constant_lut<std::int16_t>(
|
||||
exact_constant::zero, fractional_bits).wrapped_parts(), 2u);
|
||||
}
|
||||
for (unsigned fractional_bits : {0u, 16u, 31u, 32u})
|
||||
{
|
||||
EXPECT_EQ(grotto::make_exact_constant_lut<std::int32_t>(
|
||||
exact_constant::positive, fractional_bits).linear_parts(), 2u);
|
||||
EXPECT_EQ(grotto::make_exact_constant_lut<std::int64_t>(
|
||||
exact_constant::signum, fractional_bits).linear_parts(), 3u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantLut, OneProgramCoversEveryWidthAndPrecision)
|
||||
{
|
||||
// Sign programs are three constants. Projecting them onto any word yields
|
||||
// the same piece values, and the direct evaluator matches the table.
|
||||
for (unsigned fractional_bits : {0u, 4u, 8u})
|
||||
{
|
||||
const auto narrow = grotto::make_exact_constant_lut<std::int8_t>(
|
||||
exact_constant::signum, fractional_bits);
|
||||
const auto wide = grotto::make_exact_constant_lut<std::int64_t>(
|
||||
exact_constant::signum, fractional_bits);
|
||||
ASSERT_EQ(narrow.values, wide.values);
|
||||
EXPECT_EQ(narrow.values, (std::vector<std::int64_t>{-1, 0, 1}));
|
||||
EXPECT_EQ(grotto::evaluate_exact<exact_constant::signum>(std::int8_t{-5}, fractional_bits),
|
||||
narrow(-5));
|
||||
EXPECT_EQ(grotto::evaluate_exact<exact_constant::signum>(std::int64_t{5}, fractional_bits),
|
||||
wide(5));
|
||||
}
|
||||
|
||||
// ilogb is floor(log2(|raw|)) - F. Changing F only shifts that one exponent.
|
||||
EXPECT_EQ(grotto::evaluate_exact<exact_constant::ilogb>(std::int64_t{1} << 20, 4u),
|
||||
grotto::evaluate_exact<exact_constant::ilogb>(std::int64_t{1} << 20, 8u) + 4);
|
||||
|
||||
// ilog10's positive unit boundary is 10^0 from the shared pow10 table,
|
||||
// placed at raw = 2^F.
|
||||
for (unsigned fractional_bits : {0u, 4u, 8u, 16u})
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int64_t>(
|
||||
exact_constant::ilog10, fractional_bits);
|
||||
const std::int64_t unit = std::int64_t{1} << fractional_bits;
|
||||
EXPECT_EQ(lut(unit), 0) << fractional_bits;
|
||||
if (unit > 1)
|
||||
EXPECT_LT(lut(static_cast<std::int64_t>(unit - 1)), 0) << fractional_bits;
|
||||
EXPECT_EQ(grotto::evaluate_exact<exact_constant::ilog10>(unit, fractional_bits), lut(unit));
|
||||
}
|
||||
|
||||
// clz reads the integer part. Shifting the raw word and the fractional
|
||||
// width by the same amount does not change the count.
|
||||
EXPECT_EQ(grotto::evaluate_exact<exact_constant::clz>(std::int64_t{1} << 8, 0u),
|
||||
grotto::evaluate_exact<exact_constant::clz>(std::int64_t{1} << 12, 4u));
|
||||
EXPECT_EQ(grotto::evaluate_exact<exact_constant::clrsb>(std::int64_t{1} << 8, 0u),
|
||||
grotto::evaluate_exact<exact_constant::clrsb>(std::int64_t{1} << 12, 4u));
|
||||
|
||||
const unsigned fractional_bits = 4;
|
||||
for (exact_constant which : kAll)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int16_t>(which, fractional_bits);
|
||||
for (int raw = -32768; raw <= 32767; raw += 17)
|
||||
{
|
||||
const auto r = static_cast<std::int16_t>(raw);
|
||||
std::int64_t fast = 0;
|
||||
switch (which)
|
||||
{
|
||||
case exact_constant::signum:
|
||||
fast = grotto::evaluate_exact<exact_constant::signum>(r, fractional_bits); break;
|
||||
case exact_constant::positive:
|
||||
fast = grotto::evaluate_exact<exact_constant::positive>(r, fractional_bits); break;
|
||||
case exact_constant::negative:
|
||||
fast = grotto::evaluate_exact<exact_constant::negative>(r, fractional_bits); break;
|
||||
case exact_constant::nonneg:
|
||||
fast = grotto::evaluate_exact<exact_constant::nonneg>(r, fractional_bits); break;
|
||||
case exact_constant::nonpos:
|
||||
fast = grotto::evaluate_exact<exact_constant::nonpos>(r, fractional_bits); break;
|
||||
case exact_constant::zero:
|
||||
fast = grotto::evaluate_exact<exact_constant::zero>(r, fractional_bits); break;
|
||||
case exact_constant::nonzero:
|
||||
fast = grotto::evaluate_exact<exact_constant::nonzero>(r, fractional_bits); break;
|
||||
case exact_constant::ilogb:
|
||||
fast = grotto::evaluate_exact<exact_constant::ilogb>(r, fractional_bits); break;
|
||||
case exact_constant::ceil_ilogb:
|
||||
fast = grotto::evaluate_exact<exact_constant::ceil_ilogb>(r, fractional_bits); break;
|
||||
case exact_constant::ilog10:
|
||||
fast = grotto::evaluate_exact<exact_constant::ilog10>(r, fractional_bits); break;
|
||||
case exact_constant::clz:
|
||||
fast = grotto::evaluate_exact<exact_constant::clz>(r, fractional_bits); break;
|
||||
case exact_constant::clrsb:
|
||||
fast = grotto::evaluate_exact<exact_constant::clrsb>(r, fractional_bits); break;
|
||||
}
|
||||
EXPECT_EQ(fast, lut(r)) << name_of(which) << " raw=" << raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantLut, SegmentParitiesRecoverEveryInt16Sign)
|
||||
{
|
||||
const exact_constant signs[] = {
|
||||
exact_constant::signum,
|
||||
exact_constant::positive,
|
||||
exact_constant::negative,
|
||||
exact_constant::nonneg,
|
||||
exact_constant::nonpos,
|
||||
exact_constant::zero,
|
||||
exact_constant::nonzero,
|
||||
};
|
||||
for (unsigned fractional_bits : {0u, 8u, 15u})
|
||||
{
|
||||
for (exact_constant which : signs)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int16_t>(which, fractional_bits);
|
||||
ASSERT_LE(lut.bounds.size(), 3u);
|
||||
for (int raw = -32768; raw <= 32767; ++raw)
|
||||
{
|
||||
const auto alpha = static_cast<std::int16_t>(raw);
|
||||
const bool ok = lut.bounds.size() == 2
|
||||
? segment_product_matches<std::int16_t, 2>(lut, alpha)
|
||||
: segment_product_matches<std::int16_t, 3>(lut, alpha);
|
||||
EXPECT_TRUE(ok) << name_of(which) << " F=" << fractional_bits
|
||||
<< " alpha=" << raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantLut, SegmentParitiesRecoverEveryInt8Point)
|
||||
{
|
||||
const unsigned widths[] = {0u, 1u, 4u, 7u};
|
||||
for (unsigned fractional_bits : widths)
|
||||
{
|
||||
for (exact_constant which : kAll)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int8_t>(which, fractional_bits);
|
||||
ASSERT_LE(lut.bounds.size(), 40u) << name_of(which);
|
||||
for (int raw = -128; raw <= 127; ++raw)
|
||||
{
|
||||
const auto alpha = static_cast<std::int8_t>(raw);
|
||||
EXPECT_TRUE(dispatch_segments<40>(lut, alpha))
|
||||
<< name_of(which) << " F=" << fractional_bits << " alpha=" << raw
|
||||
<< " parts=" << lut.bounds.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::int64_t ref_floor_div(std::int64_t n, std::int64_t d)
|
||||
{
|
||||
if (n >= 0)
|
||||
return n / d;
|
||||
const __int128 neg = -static_cast<__int128>(n);
|
||||
return static_cast<std::int64_t>(-((neg + d - 1) / d));
|
||||
}
|
||||
|
||||
std::int64_t ref_quot(std::int64_t raw, std::int64_t modulus, std::int64_t low, std::int64_t high)
|
||||
{
|
||||
const std::int64_t clipped = raw < low ? low : (raw > high ? high : raw);
|
||||
return ref_floor_div(clipped, modulus);
|
||||
}
|
||||
|
||||
TEST(ConstantLut, CeilLogStepsUpOffPowersOfTwo)
|
||||
{
|
||||
const auto lut = grotto::make_exact_constant_lut<std::int64_t>(exact_constant::ceil_ilogb, 0);
|
||||
expect_partition(lut);
|
||||
EXPECT_EQ(lut(0), -64);
|
||||
EXPECT_EQ(lut(1), 0);
|
||||
EXPECT_EQ(lut(2), 1);
|
||||
EXPECT_EQ(lut(3), 2);
|
||||
EXPECT_EQ(lut(4), 2);
|
||||
EXPECT_EQ(lut(-3), 2);
|
||||
EXPECT_EQ(lut(-4), 2);
|
||||
// The same real value, written with 4 more fractional bits, has the same ceil log.
|
||||
EXPECT_EQ(grotto::evaluate_exact<exact_constant::ceil_ilogb>(std::int64_t{3}, 0u),
|
||||
grotto::evaluate_exact<exact_constant::ceil_ilogb>(std::int64_t{3} << 4, 4u));
|
||||
}
|
||||
|
||||
TEST(ConstantLut, ClippedQuotientIntervalAndThreshold)
|
||||
{
|
||||
// quot(3, -4, 10) on the raw grid, including the clip tails.
|
||||
const auto quot = grotto::make_clipped_quotient_lut<std::int16_t>(3, -4, 10);
|
||||
expect_partition(quot);
|
||||
for (int raw = -32768; raw <= 32767; ++raw)
|
||||
{
|
||||
const auto r = static_cast<std::int16_t>(raw);
|
||||
EXPECT_EQ(quot(r), ref_quot(r, 3, -4, 10)) << raw;
|
||||
}
|
||||
EXPECT_EQ(quot(-5), ref_floor_div(-4, 3));
|
||||
EXPECT_EQ(quot(11), ref_floor_div(10, 3));
|
||||
EXPECT_EQ(quot(0), 0);
|
||||
EXPECT_EQ(quot(3), 1);
|
||||
EXPECT_EQ(quot(-3), -1);
|
||||
|
||||
// A mathematical step of 0.5 with 2 fractional bits is raw modulus 2.
|
||||
const auto half = grotto::make_clipped_quotient_lut<std::int8_t>(2, -6, 6);
|
||||
for (int raw = -128; raw <= 127; ++raw)
|
||||
EXPECT_EQ(half(static_cast<std::int8_t>(raw)), ref_quot(raw, 2, -6, 6)) << raw;
|
||||
|
||||
const auto window = grotto::make_interval_lut<std::int8_t>(-2, 5);
|
||||
expect_partition(window);
|
||||
for (int raw = -128; raw <= 127; ++raw)
|
||||
{
|
||||
const auto r = static_cast<std::int8_t>(raw);
|
||||
EXPECT_EQ(window(r), (r >= -2 && r <= 5) ? 1 : 0) << raw;
|
||||
}
|
||||
|
||||
const auto ge = grotto::make_threshold_lut<std::int8_t>(-3, grotto::threshold_cmp::geq);
|
||||
const auto lt = grotto::make_threshold_lut<std::int8_t>(-3, grotto::threshold_cmp::lt);
|
||||
for (int raw = -128; raw <= 127; ++raw)
|
||||
{
|
||||
const auto r = static_cast<std::int8_t>(raw);
|
||||
EXPECT_EQ(ge(r), r >= -3);
|
||||
EXPECT_EQ(lt(r), r < -3);
|
||||
}
|
||||
|
||||
EXPECT_THROW(grotto::make_clipped_quotient_lut<std::int16_t>(0, -1, 1), std::invalid_argument);
|
||||
EXPECT_THROW(grotto::make_clipped_quotient_lut<std::int16_t>(1, 4, -4), std::invalid_argument);
|
||||
EXPECT_THROW(grotto::make_clipped_quotient_lut<std::int32_t>(1, -100000, 100000),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(grotto::make_interval_lut<std::int8_t>(2, -2), std::invalid_argument);
|
||||
}
|
||||
337
test/tests/context_blast_test.cpp
Normal file
337
test/tests/context_blast_test.cpp
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "grotto/prefix_parity.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
T bare(const T & v) { return v; }
|
||||
|
||||
template <typename T, std::size_t Party, dpf::sharing Scheme>
|
||||
T bare(const dpf::secret_share<T, Party, Scheme> & s) { return s.raw(); }
|
||||
|
||||
template <typename A, typename B>
|
||||
auto opened(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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
template <typename Key, typename In>
|
||||
auto ev(const Key & key, In x)
|
||||
{
|
||||
return *dpf::eval_point(key, x);
|
||||
}
|
||||
|
||||
template <typename In, typename Out>
|
||||
void every_point(In alpha, Out y, uint64_t n)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
for (uint64_t i = 0; i < n; ++i)
|
||||
{
|
||||
In q{static_cast<typename In::integral_type>(i)};
|
||||
const Out got = opened(ev(k0, q), ev(k1, q));
|
||||
EXPECT_EQ(got, q == alpha ? y : Out{}) << i;
|
||||
}
|
||||
}
|
||||
|
||||
simde__m128i g_roots[4];
|
||||
int g_ri = 0;
|
||||
simde__m128i take_root() { return g_roots[g_ri++]; }
|
||||
struct Pad
|
||||
{
|
||||
uint64_t n = 1;
|
||||
simde__m128i block()
|
||||
{
|
||||
auto v = simde_mm_set_epi64x(static_cast<long long>(n * 3),
|
||||
static_cast<long long>(n));
|
||||
n += 2;
|
||||
return v;
|
||||
}
|
||||
uint8_t bit() { return static_cast<uint8_t>((n++ >> 1) & 1u); }
|
||||
};
|
||||
void reset_roots()
|
||||
{
|
||||
g_ri = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
g_roots[i] = simde_mm_set_epi64x(0x42 * (i + 3), 0x1000 + i * 9);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ContextBlast, ModintEdgesAndFullDomain)
|
||||
{
|
||||
using m4 = dpf::modint<4>;
|
||||
using m7 = dpf::modint<7>;
|
||||
using m9 = dpf::modint<9>;
|
||||
using m10 = dpf::modint<10>;
|
||||
using m15 = dpf::modint<15>;
|
||||
|
||||
EXPECT_EQ(m4{15} + m4{1}, m4{0});
|
||||
EXPECT_EQ(m4{0} - m4{1}, m4{15});
|
||||
EXPECT_EQ(m7{127} + m7{1}, m7{0});
|
||||
EXPECT_EQ(m7{0} - m7{1}, m7{127});
|
||||
EXPECT_EQ(m9{511} + m9{1}, m9{0});
|
||||
EXPECT_EQ(m10{1023} + m10{1}, m10{0});
|
||||
EXPECT_EQ(m15{32767} + m15{1}, m15{0});
|
||||
|
||||
// A uint8 leaf needs 4 index bits, so the domain must be wider than that.
|
||||
every_point(m4{0}, uint32_t{1}, 16);
|
||||
every_point(m4{15}, uint32_t{9}, 16);
|
||||
every_point(m7{0}, uint32_t{3}, 128);
|
||||
every_point(m7{1}, uint32_t{3}, 128);
|
||||
every_point(m7{127}, uint32_t{8}, 128);
|
||||
every_point(m7{64}, dpf::xor_wrapper<uint32_t>{0x00ff}, 128);
|
||||
|
||||
for (unsigned a : {0u, 1u, 511u, 512u, 1023u})
|
||||
every_point(m10{a}, uint32_t{0xabcdu}, 1024);
|
||||
|
||||
every_point(m9{0}, uint16_t{2}, 512);
|
||||
every_point(m9{511}, uint16_t{2}, 512);
|
||||
every_point(m15{0}, uint32_t{1}, 32768);
|
||||
every_point(m15{32767}, uint32_t{7}, 32768);
|
||||
}
|
||||
|
||||
TEST(ContextBlast, KeywordBinaryAndOctal)
|
||||
{
|
||||
using bin = dpf::keyword<4, dpf::alphabets::binary>;
|
||||
using oct = dpf::keyword<2, dpf::alphabets::octal>;
|
||||
const uint16_t y = 0x1234;
|
||||
const char *bins[] = {"0000", "0001", "0010", "0111", "1000", "1111"};
|
||||
for (const char *s : bins)
|
||||
{
|
||||
bin alpha{s};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
for (unsigned i = 0; i < 16; ++i)
|
||||
{
|
||||
char buf[5] = {'0', '0', '0', '0', 0};
|
||||
for (int b = 0; b < 4; ++b)
|
||||
buf[3 - b] = ((i >> b) & 1u) ? '1' : '0';
|
||||
bin q{buf};
|
||||
EXPECT_EQ(opened(ev(k0, q), ev(k1, q)), q == alpha ? y : uint16_t{0})
|
||||
<< s << " vs " << buf;
|
||||
}
|
||||
}
|
||||
oct alpha{"07"};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, uint8_t{5});
|
||||
oct hit{"07"};
|
||||
oct miss{"10"};
|
||||
oct zero{"00"};
|
||||
EXPECT_EQ(opened(ev(k0, hit), ev(k1, hit)), uint8_t{5});
|
||||
EXPECT_EQ(opened(ev(k0, miss), ev(k1, miss)), uint8_t{0});
|
||||
EXPECT_EQ(opened(ev(k0, zero), ev(k1, zero)), uint8_t{0});
|
||||
EXPECT_THROW(oct{"89"}, std::domain_error);
|
||||
EXPECT_THROW(bin{"2"}, std::domain_error);
|
||||
}
|
||||
|
||||
TEST(ContextBlast, BitstringPointIntervalSequence)
|
||||
{
|
||||
using bs = dpf::bitstring<6>;
|
||||
const uint32_t y = 0x11111111u;
|
||||
for (unsigned a : {0u, 1u, 31u, 32u, 63u})
|
||||
{
|
||||
bs alpha{a};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
for (unsigned i = 0; i < 64; ++i)
|
||||
{
|
||||
bs q{i};
|
||||
EXPECT_EQ(opened(ev(k0, q), ev(k1, q)), q == alpha ? y : 0u) << i;
|
||||
}
|
||||
bs from{0};
|
||||
bs to{63};
|
||||
auto iv0 = dpf::eval_interval(k0, from, to);
|
||||
auto iv1 = dpf::eval_interval(k1, from, to);
|
||||
auto p0 = std::begin(iv0.second);
|
||||
auto p1 = std::begin(iv1.second);
|
||||
for (unsigned i = 0; i < 64; ++i, ++p0, ++p1)
|
||||
EXPECT_EQ(opened(*p0, *p1), i == a ? y : 0u);
|
||||
EXPECT_EQ(p0, std::end(iv0.second));
|
||||
|
||||
std::vector<bs> seq{bs{63}, bs{0}, alpha, bs{1}, alpha};
|
||||
std::vector<bs> sorted = seq;
|
||||
std::sort(sorted.begin(), sorted.end());
|
||||
auto recipe = dpf::make_sequence_recipe(k0, sorted.begin(), sorted.end());
|
||||
auto s0 = dpf::eval_sequence(k0, recipe);
|
||||
auto s1 = dpf::eval_sequence(k1, recipe);
|
||||
auto q0 = std::begin(s0.second);
|
||||
auto q1 = std::begin(s1.second);
|
||||
for (bs x : sorted)
|
||||
{
|
||||
EXPECT_EQ(opened(*q0, *q1), x == alpha ? y : 0u);
|
||||
++q0;
|
||||
++q1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ContextBlast, ComparisonKindsSignedAndUnsigned)
|
||||
{
|
||||
auto check = [](auto alpha, auto kind_keys, auto pred) {
|
||||
auto [k0, k1] = kind_keys;
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
using In = decltype(alpha);
|
||||
constexpr auto bits = dpf::utils::bitlength_of_v<In>;
|
||||
const uint64_t n = uint64_t{1} << (bits > 8 ? 8 : bits);
|
||||
for (uint64_t i = 0; i < n; ++i)
|
||||
{
|
||||
In q;
|
||||
if constexpr (std::is_integral_v<In>)
|
||||
q = static_cast<In>(i);
|
||||
else
|
||||
q = In{static_cast<typename In::integral_type>(i)};
|
||||
const auto got = opened(dpf::eval_point(dpf::cmp, k0, q),
|
||||
dpf::eval_point(dpf::cmp, k1, q)) & mask;
|
||||
const uint64_t want = pred(q, alpha) ? 4u : 1u;
|
||||
EXPECT_EQ(got, want) << i;
|
||||
}
|
||||
};
|
||||
check(uint8_t{10}, dpf::make_dpf(uint8_t{10}, dpf::lt(uint64_t{4}, uint64_t{1})),
|
||||
[](uint8_t q, uint8_t a) { return q < a; });
|
||||
check(uint8_t{10}, dpf::make_dpf(uint8_t{10}, dpf::leq(uint64_t{4}, uint64_t{1})),
|
||||
[](uint8_t q, uint8_t a) { return q <= a; });
|
||||
check(uint8_t{10}, dpf::make_dpf(uint8_t{10}, dpf::gt(uint64_t{4}, uint64_t{1})),
|
||||
[](uint8_t q, uint8_t a) { return q > a; });
|
||||
check(uint8_t{10}, dpf::make_dpf(uint8_t{10}, dpf::geq(uint64_t{4}, uint64_t{1})),
|
||||
[](uint8_t q, uint8_t a) { return q >= a; });
|
||||
check(uint8_t{0}, dpf::make_dpf(uint8_t{0}, dpf::lt(uint64_t{4}, uint64_t{1})),
|
||||
[](uint8_t q, uint8_t a) { return q < a; });
|
||||
check(uint8_t{255}, dpf::make_dpf(uint8_t{255}, dpf::leq(uint64_t{4}, uint64_t{1})),
|
||||
[](uint8_t q, uint8_t a) { return q <= a; });
|
||||
check(int8_t{-1}, dpf::make_dpf(int8_t{-1}, dpf::lt(uint64_t{4}, uint64_t{1})),
|
||||
[](int8_t q, int8_t a) { return q < a; });
|
||||
check(int8_t{-128}, dpf::make_dpf(int8_t{-128}, dpf::gt(uint64_t{4}, uint64_t{1})),
|
||||
[](int8_t q, int8_t a) { return q > a; });
|
||||
using m = dpf::modint<8>;
|
||||
check(m{200}, dpf::make_dpf(m{200}, dpf::lt(uint64_t{4}, uint64_t{1})),
|
||||
[](m q, m a) { return q < a; });
|
||||
}
|
||||
|
||||
TEST(ContextBlast, IncrementalSlotsAndInnerProduct)
|
||||
{
|
||||
const uint16_t x = 0x81fe;
|
||||
auto [k0, k1] = dpf::make_dpf(x, dpf::at<8>(uint8_t{7}), dpf::at<12>(uint16_t{99}),
|
||||
uint32_t{5});
|
||||
for (uint16_t q : {uint16_t{0}, uint16_t{1}, x, uint16_t{0x8000}, uint16_t{0xffff},
|
||||
static_cast<uint16_t>(x ^ 1u), static_cast<uint16_t>(x ^ 0x0100u)})
|
||||
{
|
||||
const auto lane8 = static_cast<uint16_t>(q >> 8);
|
||||
const auto alane = static_cast<uint16_t>(x >> 8);
|
||||
EXPECT_EQ(opened(*dpf::eval_point(dpf::out<0, 8>, k0, q),
|
||||
*dpf::eval_point(dpf::out<0, 8>, k1, q)),
|
||||
lane8 == alane ? uint8_t{7} : uint8_t{0}) << q;
|
||||
const auto lane12 = static_cast<uint16_t>(q >> 4);
|
||||
const auto blane = static_cast<uint16_t>(x >> 4);
|
||||
EXPECT_EQ(opened(*dpf::eval_point(dpf::out<1, 12>, k0, q),
|
||||
*dpf::eval_point(dpf::out<1, 12>, k1, q)),
|
||||
lane12 == blane ? uint16_t{99} : uint16_t{0}) << q;
|
||||
EXPECT_EQ(opened(*dpf::eval_point(dpf::out<2>, k0, q),
|
||||
*dpf::eval_point(dpf::out<2>, k1, q)),
|
||||
q == x ? uint32_t{5} : uint32_t{0}) << q;
|
||||
}
|
||||
|
||||
const uint8_t alpha = 20;
|
||||
const uint32_t beta = 9;
|
||||
auto [p0, p1] = dpf::make_dpf(alpha, beta);
|
||||
// Weights follow the leaf-aligned interval layout: a uint32 leaf is 4
|
||||
// inputs, so [10, 30] is emitted from input 8 through 31.
|
||||
const uint8_t from = 10, to = 30;
|
||||
const uint8_t leaf = 4;
|
||||
const uint8_t begin = static_cast<uint8_t>(from & ~(leaf - 1u));
|
||||
const uint8_t end = static_cast<uint8_t>((to | (leaf - 1u)));
|
||||
std::vector<uint32_t> w(end - begin + 1);
|
||||
uint32_t expect = 0;
|
||||
for (uint8_t q = begin; q <= end; ++q)
|
||||
{
|
||||
w[q - begin] = q * 3u + 1u;
|
||||
if (q == alpha)
|
||||
expect = beta * w[q - begin];
|
||||
}
|
||||
auto memo0 = dpf::make_basic_interval_memoizer(p0, from, to);
|
||||
auto memo1 = dpf::make_basic_interval_memoizer(p1, from, to);
|
||||
auto ip0 = dpf::eval_inner_product<0>(p0, from, to, w, memo0);
|
||||
auto ip1 = dpf::eval_inner_product<0>(p1, from, to, w, memo1);
|
||||
EXPECT_EQ(opened(ip0, ip1), expect);
|
||||
}
|
||||
|
||||
TEST(ContextBlast, XorWrapperAndGenevalIntegers)
|
||||
{
|
||||
using X = dpf::xor_wrapper<uint32_t>;
|
||||
const uint16_t alpha = 0x00ff;
|
||||
const X y{0xa5a5a5a5u};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
for (uint16_t q : {uint16_t{0}, uint16_t{1}, alpha, uint16_t{0x0100},
|
||||
uint16_t{0x8000}, uint16_t{0xffff}, static_cast<uint16_t>(alpha ^ 1u)})
|
||||
EXPECT_EQ(opened(ev(k0, q), ev(k1, q)), q == alpha ? y : X{0});
|
||||
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf(int32_t{-2},
|
||||
dpf::root_sampler_t<dpf::prg::aes128>{take_root}, X{7});
|
||||
const int32_t x0 = 5;
|
||||
const int32_t secret = -2;
|
||||
const int32_t x1 = secret ^ x0;
|
||||
reset_roots();
|
||||
auto g = dpf::geneval_point(x0, x1, secret,
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, X{7});
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
EXPECT_EQ(g.live_levels, std::decay_t<decltype(keys.first)>::depth);
|
||||
EXPECT_EQ(opened(g.party0[0], g.party1[0]), X{7});
|
||||
EXPECT_EQ(g.party0[0], bare(ev(keys.first, secret)));
|
||||
|
||||
const int32_t far = 100;
|
||||
reset_roots();
|
||||
auto off = dpf::geneval_point(x0, x1, far,
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, X{7});
|
||||
EXPECT_FALSE(off.leaf_live);
|
||||
EXPECT_GT(off.live_levels, 0u);
|
||||
EXPECT_LT(off.live_levels, off.correction_words.size());
|
||||
for (std::size_t i = 0; i < off.live_levels; ++i)
|
||||
EXPECT_EQ(std::memcmp(&off.correction_words[i], &keys.first.correction_word(i),
|
||||
sizeof(simde__m128i)), 0);
|
||||
EXPECT_EQ(opened(off.party0[0], off.party1[0]), X{0});
|
||||
|
||||
const uint32_t u = 0x80000001u;
|
||||
const uint32_t u0 = 0x11111111u;
|
||||
const uint32_t u1 = u ^ u0;
|
||||
reset_roots();
|
||||
auto uk = dpf::make_dpf(u, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
uint64_t{99});
|
||||
reset_roots();
|
||||
const uint32_t qs[] = {0u, 1u, u, u ^ 1u, 0xffffffffu};
|
||||
auto sq = dpf::geneval_sequence(u0, u1, std::begin(qs), std::end(qs),
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, uint64_t{99});
|
||||
EXPECT_TRUE(sq.leaf_live);
|
||||
for (std::size_t i = 0; i < sq.live_levels; ++i)
|
||||
EXPECT_EQ(std::memcmp(&sq.correction_words[i], &uk.first.correction_word(i),
|
||||
sizeof(simde__m128i)), 0);
|
||||
for (std::size_t i = 0; i < 5; ++i)
|
||||
EXPECT_EQ(opened(sq.party0[i], sq.party1[i]), qs[i] == u ? uint64_t{99} : 0u);
|
||||
}
|
||||
|
||||
TEST(ContextBlast, PrefixParityAgreesAcrossParties)
|
||||
{
|
||||
const uint8_t alpha = 0x3c;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::bit::one);
|
||||
const std::array<uint8_t, 4> ends{0, 1, alpha, 255};
|
||||
auto [p0, n0] = grotto::prefix_parities(k0, ends);
|
||||
auto [p1, n1] = grotto::prefix_parities(k1, ends);
|
||||
(void)n0;
|
||||
(void)n1;
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const bool bit = p0[i] ^ p1[i];
|
||||
bool acc = false;
|
||||
for (uint8_t q = 0; q < ends[i]; ++q)
|
||||
acc ^= (opened(ev(k0, q), ev(k1, q)) == dpf::bit::one);
|
||||
EXPECT_EQ(bit, acc) << int(ends[i]);
|
||||
}
|
||||
}
|
||||
208
test/tests/dpf_key_test.cpp
Normal file
208
test/tests/dpf_key_test.cpp
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
simde__m128i fake_root_sampler()
|
||||
{
|
||||
static int64_t ret_int = 0x4;
|
||||
simde__m128i ret = {ret_int, 0};
|
||||
ret_int <<= 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST(DpfKeyTest, HardCodedGenCheck)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using output_type = uint32_t;
|
||||
input_type x = 0xAA; // = 0b 1010 1010
|
||||
output_type y0 = 0xAAAAAAAA; // additive / subtractive share
|
||||
dpf::xor_wrapper<output_type> y1 = dpf::xor_wrapper<output_type>(0x55555555); // xor share
|
||||
dpf::wildcard_value<output_type> y2 = dpf::wildcard_value<output_type>(); // wildcard
|
||||
auto [dpf0, dpf1] = dpf::make_dpf<dpf::prg::aes128, dpf::prg::aes128, &fake_root_sampler>(x, y0, y1, y2);
|
||||
|
||||
// 128-bit representation of 0x4 with lowest bit unset
|
||||
ASSERT_EQ(dpf0.root()[1], 0);
|
||||
ASSERT_EQ(dpf0.root()[0], 0x4);
|
||||
// 128-bit representation of 0x8 with lowest bit set
|
||||
ASSERT_EQ(dpf1.root()[1], 0);
|
||||
ASSERT_EQ(dpf1.root()[0], 0x9);
|
||||
|
||||
ASSERT_EQ(dpf0.correction_words()[0][1], 0x7ff85a65ce2111c9);
|
||||
ASSERT_EQ(dpf0.correction_words()[0][0], 0x36863b84ab3944d2);
|
||||
ASSERT_EQ(dpf0.correction_words()[0][1], dpf1.correction_words()[0][1]);
|
||||
ASSERT_EQ(dpf0.correction_words()[0][0], dpf1.correction_words()[0][0]);
|
||||
ASSERT_EQ(dpf0.correction_advice()[0], 0b00);
|
||||
ASSERT_EQ(dpf0.correction_advice()[0], dpf1.correction_advice()[0]);
|
||||
|
||||
// dpf0 after level 0:
|
||||
// 0xc4c4bd72d02958c541201f063e3c1173
|
||||
// dpf1 after level 0:
|
||||
// 0xdd09c23385ba379378631a3a9c46f52e
|
||||
|
||||
ASSERT_EQ(dpf0.correction_words()[1][1], 0x9ca0f55370cf6bfe);
|
||||
ASSERT_EQ(dpf0.correction_words()[1][0], 0xc3b9e951c500d272);
|
||||
ASSERT_EQ(dpf0.correction_words()[1][1], dpf1.correction_words()[1][1]);
|
||||
ASSERT_EQ(dpf0.correction_words()[1][0], dpf1.correction_words()[1][0]);
|
||||
ASSERT_EQ(dpf0.correction_advice()[1], 0b01);
|
||||
ASSERT_EQ(dpf0.correction_advice()[1], dpf1.correction_advice()[1]);
|
||||
|
||||
// dpf0 after level 1:
|
||||
// 0x2bef771157872382accfcf2a5e2f7e57
|
||||
// dpf1 after level 1:
|
||||
// 0x7604b860b26e8586b0c6ad05ec6886ce
|
||||
|
||||
ASSERT_EQ(dpf0.correction_words()[2][1], 0x886f1eb652b72eda);
|
||||
ASSERT_EQ(dpf0.correction_words()[2][0], 0x0ff98303eca43ab6);
|
||||
ASSERT_EQ(dpf0.correction_words()[2][1], dpf1.correction_words()[2][1]);
|
||||
ASSERT_EQ(dpf0.correction_words()[2][0], dpf1.correction_words()[2][0]);
|
||||
ASSERT_EQ(dpf0.correction_advice()[2], 0b10);
|
||||
ASSERT_EQ(dpf0.correction_advice()[2], dpf1.correction_advice()[2]);
|
||||
|
||||
// dpf0 after level 2:
|
||||
// 0x39adfa95d94a10fdff65a956019f0a6c
|
||||
// dpf1 after level 2:
|
||||
// 0x59be9dba7aa04f9a12d23cd995d90135
|
||||
|
||||
ASSERT_EQ(dpf0.correction_words()[3][1], 0x4e69100f5b844cb9);
|
||||
ASSERT_EQ(dpf0.correction_words()[3][0], 0x9ac5b5baba9a193b);
|
||||
ASSERT_EQ(dpf0.correction_words()[3][1], dpf1.correction_words()[3][1]);
|
||||
ASSERT_EQ(dpf0.correction_words()[3][0], dpf1.correction_words()[3][0]);
|
||||
ASSERT_EQ(dpf0.correction_advice()[3], 0b10);
|
||||
ASSERT_EQ(dpf0.correction_advice()[3], dpf1.correction_advice()[3]);
|
||||
|
||||
// dpf0 after level 3:
|
||||
// 0x028922e3e5fca1a824a12136fc2ed7e3
|
||||
// dpf1 after level 3:
|
||||
// 0xd7699bb72bb9e8d42363e899692ecf36
|
||||
|
||||
ASSERT_EQ(dpf0.correction_words()[4][1], 0xe701887629e08652);
|
||||
ASSERT_EQ(dpf0.correction_words()[4][0], 0xbd92c2853e1e2457);
|
||||
ASSERT_EQ(dpf0.correction_words()[4][1], dpf1.correction_words()[4][1]);
|
||||
ASSERT_EQ(dpf0.correction_words()[4][0], dpf1.correction_words()[4][0]);
|
||||
ASSERT_EQ(dpf0.correction_advice()[4], 0b01);
|
||||
ASSERT_EQ(dpf0.correction_advice()[4], dpf1.correction_advice()[4]);
|
||||
|
||||
// dpf0 after level 4:
|
||||
// 0xe0deacc7c5f61d83aebacde0bd97f61f
|
||||
// dpf1 after level 4:
|
||||
// 0x96be3cfb09b9bc84e0a6de756d9589f2
|
||||
|
||||
ASSERT_EQ(dpf0.correction_words()[5][1], 0xc8edc84047a7b3df);
|
||||
ASSERT_EQ(dpf0.correction_words()[5][0], 0xbc0d1f614b01d608);
|
||||
ASSERT_EQ(dpf0.correction_words()[5][1], dpf1.correction_words()[5][1]);
|
||||
ASSERT_EQ(dpf0.correction_words()[5][0], dpf1.correction_words()[5][0]);
|
||||
ASSERT_EQ(dpf0.correction_advice()[5], 0b01);
|
||||
ASSERT_EQ(dpf0.correction_advice()[5], dpf1.correction_advice()[5]);
|
||||
|
||||
// dpf0 after level 5:
|
||||
// 0x3cb3c5060d58e866c703b4b7939725b8
|
||||
// dpf1 after level 5:
|
||||
// 0x1afcd5c2a2a3f4b9be5b9564585df4f3
|
||||
|
||||
// Leaf layer
|
||||
|
||||
// dpf0 make leaf mask inner:
|
||||
// 0: bb994bbd eba3cbb2 39b39032 e5f31930
|
||||
// 1: d32db0c1 3da76455 961fadd7 4b5d7350
|
||||
// 2: 5de4be73 fd14043f 19b22bba be0ff8f8
|
||||
// dpf1 make leaf mask inner:
|
||||
// 0: 921bb1c5 b0a6c8c2 484ae275 9a752740
|
||||
// 1: 279a2459 0d9d913f f1bf8700 fc603f6a
|
||||
// 2: cb839afd 6a68b9cf b0c6aac6 7dd6f9ad
|
||||
// naked masks:
|
||||
// 0: 00000000 aaaaaaaa 00000000 00000000
|
||||
// 1: 00000000 55555555 00000000 00000000
|
||||
// 2: 00000000 00000000 00000000 00000000
|
||||
// correction words:
|
||||
// 0: d6826608 1a585266 0e975243 b4820e10
|
||||
// 1: 546c7398 7aa0d795 5b9fd929 b102cc1a
|
||||
// 2: 6d9edc8a 6d54b590 97147f0c bfc700b5
|
||||
|
||||
ASSERT_EQ(dpf0.leaf<0>()[1], 0xd68266081a585266);
|
||||
ASSERT_EQ(dpf0.leaf<0>()[0], 0x0e975243b4820e10);
|
||||
ASSERT_EQ(dpf0.leaf<0>()[1], dpf1.leaf<0>()[1]);
|
||||
ASSERT_EQ(dpf0.leaf<0>()[0], dpf1.leaf<0>()[0]);
|
||||
|
||||
ASSERT_EQ(dpf0.leaf<1>()[1], 0xf4b79498656fa03f);
|
||||
ASSERT_EQ(dpf0.leaf<1>()[0], 0x67a02ad7b73d4c3a);
|
||||
ASSERT_EQ(dpf0.leaf<1>()[1], dpf1.leaf<1>()[1]);
|
||||
ASSERT_EQ(dpf0.leaf<1>()[0], dpf1.leaf<1>()[0]);
|
||||
|
||||
// vector:
|
||||
// [0|0|1|0] which corresponds to input x
|
||||
// lsb of "dpf0 after leaf 5" is 0 (used as sign bit)
|
||||
// => output_type(2*sign-1) = output_type(2*0-1) = 0xFFFFFFFF
|
||||
simde__m128i vector{0x0000000000000000, 0x00000000FFFFFFFF},
|
||||
blinded0 = simde_mm_add_epi32(vector, dpf1.beaver<2>().vector_blind),
|
||||
blinded1 = simde_mm_add_epi32(vector, dpf0.beaver<2>().vector_blind),
|
||||
mulleaf0 = simde_mm_mullo_epi32(dpf0.beaver<2>().vector_blind, simde_mm_set1_epi32(dpf1.beaver<2>().output_blind)),
|
||||
mulleaf1 = simde_mm_mullo_epi32(dpf1.beaver<2>().vector_blind, simde_mm_set1_epi32(dpf0.beaver<2>().output_blind)),
|
||||
leaf = simde_mm_sub_epi32(simde_mm_add_epi32(dpf0.leaf<2>(), dpf1.leaf<2>()),
|
||||
simde_mm_add_epi32(mulleaf0, mulleaf1));
|
||||
|
||||
ASSERT_EQ(blinded0[1], dpf0.beaver<2>().blinded_vector[1]);
|
||||
ASSERT_EQ(blinded0[0], dpf0.beaver<2>().blinded_vector[0]);
|
||||
ASSERT_EQ(blinded1[1], dpf1.beaver<2>().blinded_vector[1]);
|
||||
ASSERT_EQ(blinded1[0], dpf1.beaver<2>().blinded_vector[0]);
|
||||
ASSERT_EQ(leaf[1], 0x6d9edc8a6d54b590);
|
||||
ASSERT_EQ(leaf[0], 0x97147f0cbfc700b5);
|
||||
|
||||
ASSERT_EQ(dpf0.is_wildcard(0), false);
|
||||
ASSERT_EQ(dpf0.is_wildcard(1), false);
|
||||
ASSERT_EQ(dpf0.is_wildcard(2), true);
|
||||
ASSERT_EQ(dpf1.is_wildcard(0), false);
|
||||
ASSERT_EQ(dpf1.is_wildcard(1), false);
|
||||
ASSERT_EQ(dpf1.is_wildcard(2), true);
|
||||
}
|
||||
|
||||
TEST(DpfKeyTest, MakeDpfRandomPoint)
|
||||
{
|
||||
using prg_type = dpf::prg::aes128;
|
||||
using input_type = uint8_t;
|
||||
using output_type = uint32_t;
|
||||
using output_type0 = std::make_signed_t<output_type>;
|
||||
using output_type1 = std::make_unsigned_t<output_type>;
|
||||
using output_type2 = dpf::xor_wrapper<output_type>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<prg_type, prg_type, input_type, output_type0, output_type1, output_type2>;
|
||||
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output0 = dpf::utils::make_from_integral_value<output_type0>{};
|
||||
static constexpr auto from_integral_type_output1 = dpf::utils::make_from_integral_value<output_type1>{};
|
||||
static constexpr auto from_integral_type_output2 = dpf::utils::make_from_integral_value<output_type2>{};
|
||||
output_type0 zero_output0 = from_integral_type_output0(0),
|
||||
one_output0 = from_integral_type_output0(1);
|
||||
output_type1 zero_output1 = from_integral_type_output1(0),
|
||||
one_output1 = from_integral_type_output1(1);
|
||||
output_type2 zero_output2 = from_integral_type_output2(0),
|
||||
one_output2 = from_integral_type_output2(1);
|
||||
|
||||
auto [dpf0, dpf1, x0, x1] = dpf::make_dpf_random_point<dpf_type>();
|
||||
input_type x = x0 + x1;
|
||||
|
||||
auto [buf0, iter0] = dpf::eval_full<0, 1, 2>(dpf0);
|
||||
auto [buf1, iter1] = dpf::eval_full<0, 1, 2>(dpf1);
|
||||
|
||||
auto zip0 = dpf::tuple_as_zip(iter0);
|
||||
auto zip1 = dpf::tuple_as_zip(iter1);
|
||||
auto it0 = std::cbegin(zip0);
|
||||
auto it1 = std::cbegin(zip1);
|
||||
|
||||
input_type cur = from_integral_type(0);
|
||||
for (std::size_t i = 0; i < 1ul << dpf::utils::bitlength_of_v<input_type>; ++i, ++cur, ++it0, ++it1)
|
||||
{
|
||||
if (cur == x)
|
||||
{
|
||||
ASSERT_EQ(static_cast<output_type0>(dpf::reconstruct(std::get<0>(*it0), std::get<0>(*it1))), one_output0);
|
||||
ASSERT_EQ(static_cast<output_type1>(dpf::reconstruct(std::get<1>(*it0), std::get<1>(*it1))), one_output1);
|
||||
ASSERT_EQ(static_cast<output_type2>(dpf::reconstruct(std::get<2>(*it0), std::get<2>(*it1))), one_output2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(static_cast<output_type0>(dpf::reconstruct(std::get<0>(*it0), std::get<0>(*it1))), zero_output0);
|
||||
ASSERT_EQ(static_cast<output_type1>(dpf::reconstruct(std::get<1>(*it0), std::get<1>(*it1))), zero_output1);
|
||||
ASSERT_EQ(static_cast<output_type2>(dpf::reconstruct(std::get<2>(*it0), std::get<2>(*it1))), zero_output2);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(zip0));
|
||||
ASSERT_EQ(it1, std::end(zip1));
|
||||
}
|
||||
166
test/tests/easy_lut_test.cpp
Normal file
166
test/tests/easy_lut_test.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "grotto/easy_lut.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::int64_t round_div(__int128 num, __int128 den)
|
||||
{
|
||||
const bool neg = num < 0;
|
||||
const __int128 mag = neg ? -num : num;
|
||||
const __int128 q = (mag + den / 2) / den;
|
||||
return static_cast<std::int64_t>(neg ? -q : q);
|
||||
}
|
||||
|
||||
std::int64_t ref_abs(std::int64_t raw) { return raw < 0 ? -raw : raw; }
|
||||
std::int64_t ref_relu(std::int64_t raw) { return raw < 0 ? 0 : raw; }
|
||||
|
||||
std::int64_t ref_clip(std::int64_t raw, std::int64_t low, std::int64_t high)
|
||||
{
|
||||
if (raw < low)
|
||||
return low;
|
||||
if (raw > high)
|
||||
return high;
|
||||
return raw;
|
||||
}
|
||||
|
||||
std::int64_t ref_hardsigmoid(std::int64_t raw, std::int64_t three, std::int64_t one)
|
||||
{
|
||||
if (raw <= -three)
|
||||
return 0;
|
||||
if (raw >= three)
|
||||
return one;
|
||||
return round_div(raw + three, 6);
|
||||
}
|
||||
|
||||
std::int64_t ref_hardswish(std::int64_t raw, std::int64_t three, std::int64_t den)
|
||||
{
|
||||
if (raw <= -three)
|
||||
return 0;
|
||||
if (raw >= three)
|
||||
return raw;
|
||||
return round_div(__int128(raw) * (raw + three), den);
|
||||
}
|
||||
|
||||
std::int64_t ref_sqrelu(std::int64_t raw, std::int64_t den)
|
||||
{
|
||||
if (raw < 0)
|
||||
return 0;
|
||||
return round_div(__int128(raw) * raw, den);
|
||||
}
|
||||
|
||||
std::int64_t ref_soft(std::int64_t raw, std::int64_t knot)
|
||||
{
|
||||
if (raw > knot)
|
||||
return raw - knot;
|
||||
if (raw < -knot)
|
||||
return raw + knot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::int64_t ref_hardshrink(std::int64_t raw, std::int64_t knot)
|
||||
{
|
||||
if (raw > knot || raw < -knot)
|
||||
return raw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Raw, typename Fn>
|
||||
void expect_all(const grotto::easy_lut<Raw> & lut, Fn && ref)
|
||||
{
|
||||
using lim = std::numeric_limits<Raw>;
|
||||
for (std::int64_t raw = lim::min(); raw <= lim::max(); ++raw)
|
||||
{
|
||||
EXPECT_EQ(lut(static_cast<Raw>(raw)), ref(raw)) << raw;
|
||||
if (raw == lim::max())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(EasyLut, FewPiecesAtEveryPrecision)
|
||||
{
|
||||
EXPECT_EQ((grotto::make_abs_lut<std::int16_t>().parts()), 2u);
|
||||
EXPECT_EQ((grotto::make_relu_lut<std::int16_t>().parts()), 2u);
|
||||
EXPECT_EQ((grotto::make_squared_relu_lut<std::int16_t>(0).parts()), 2u);
|
||||
EXPECT_EQ((grotto::make_leaky_relu_lut<std::int16_t>(0).parts()), 1u);
|
||||
EXPECT_EQ((grotto::make_leaky_relu_lut<std::int16_t>(3).parts()), 2u);
|
||||
|
||||
for (unsigned fractional_bits : {0u, 2u, 4u})
|
||||
{
|
||||
EXPECT_EQ((grotto::make_relu6_lut<std::int16_t>(fractional_bits).parts()), 3u);
|
||||
EXPECT_EQ((grotto::make_hardtanh_lut<std::int16_t>(fractional_bits).parts()), 3u);
|
||||
EXPECT_EQ((grotto::make_softshrink_lut<std::int16_t>(fractional_bits).parts()), 3u);
|
||||
EXPECT_EQ((grotto::make_hardshrink_lut<std::int16_t>(fractional_bits).parts()), 3u);
|
||||
EXPECT_EQ((grotto::make_hardsigmoid_lut<std::int16_t>(fractional_bits).parts()), 3u);
|
||||
EXPECT_EQ((grotto::make_hardswish_lut<std::int16_t>(fractional_bits).parts()), 3u);
|
||||
}
|
||||
|
||||
// On int8 with 7 fractional bits, ±1 and ±3 lie outside the domain.
|
||||
EXPECT_EQ((grotto::make_hardtanh_lut<std::int8_t>(7).parts()), 1u);
|
||||
EXPECT_EQ((grotto::make_hardsigmoid_lut<std::int8_t>(7).parts()), 1u);
|
||||
}
|
||||
|
||||
TEST(EasyLut, ExactLinesMatchOnInt16)
|
||||
{
|
||||
for (unsigned fractional_bits : {0u, 3u})
|
||||
{
|
||||
const std::int64_t scale = std::int64_t{1} << fractional_bits;
|
||||
const auto abs_lut = grotto::make_abs_lut<std::int16_t>(fractional_bits);
|
||||
const auto relu = grotto::make_relu_lut<std::int16_t>(fractional_bits);
|
||||
const auto relu6 = grotto::make_relu6_lut<std::int16_t>(fractional_bits);
|
||||
const auto tanh = grotto::make_hardtanh_lut<std::int16_t>(fractional_bits);
|
||||
const auto soft = grotto::make_softshrink_lut<std::int16_t>(fractional_bits);
|
||||
const auto shrink = grotto::make_hardshrink_lut<std::int16_t>(fractional_bits);
|
||||
const auto sig = grotto::make_hardsigmoid_lut<std::int16_t>(fractional_bits);
|
||||
const auto swish = grotto::make_hardswish_lut<std::int16_t>(fractional_bits);
|
||||
const auto sq = grotto::make_squared_relu_lut<std::int16_t>(fractional_bits);
|
||||
const auto leak = grotto::make_leaky_relu_lut<std::int16_t>(2);
|
||||
const std::int64_t three = 3 * scale;
|
||||
const std::int64_t den = 6 * scale;
|
||||
expect_all<std::int16_t>(abs_lut, ref_abs);
|
||||
expect_all<std::int16_t>(relu, ref_relu);
|
||||
expect_all<std::int16_t>(relu6, [&](std::int64_t raw) {
|
||||
return ref_clip(raw, 0, 6 * scale);
|
||||
});
|
||||
expect_all<std::int16_t>(tanh, [&](std::int64_t raw) {
|
||||
return ref_clip(raw, -scale, scale);
|
||||
});
|
||||
expect_all<std::int16_t>(soft, [&](std::int64_t raw) { return ref_soft(raw, scale); });
|
||||
expect_all<std::int16_t>(shrink, [&](std::int64_t raw) { return ref_hardshrink(raw, scale); });
|
||||
expect_all<std::int16_t>(sig, [&](std::int64_t raw) {
|
||||
return ref_hardsigmoid(raw, three, scale);
|
||||
});
|
||||
expect_all<std::int16_t>(swish, [&](std::int64_t raw) {
|
||||
return ref_hardswish(raw, three, den);
|
||||
});
|
||||
expect_all<std::int16_t>(sq, [&](std::int64_t raw) { return ref_sqrelu(raw, scale); });
|
||||
expect_all<std::int16_t>(leak, [](std::int64_t raw) {
|
||||
return raw >= 0 ? raw : round_div(raw, 4);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EasyLut, ClipIsTheGeneralProgram)
|
||||
{
|
||||
const auto relu6 = grotto::make_relu6_lut<std::int16_t>(2);
|
||||
const auto clip = grotto::make_clip_lut<std::int16_t>(2, 0, 6);
|
||||
EXPECT_EQ(relu6.parts(), clip.parts());
|
||||
EXPECT_EQ(relu6.bounds, clip.bounds);
|
||||
EXPECT_EQ(relu6.c0, clip.c0);
|
||||
EXPECT_EQ(relu6.c1, clip.c1);
|
||||
}
|
||||
|
||||
TEST(EasyLut, AbsAndReluIgnoreFractionalWidth)
|
||||
{
|
||||
const auto a0 = grotto::make_abs_lut<std::int32_t>(0);
|
||||
const auto a8 = grotto::make_abs_lut<std::int32_t>(8);
|
||||
EXPECT_EQ(a0.c0, a8.c0);
|
||||
EXPECT_EQ(a0.c1, a8.c1);
|
||||
EXPECT_EQ(a0.bounds, a8.bounds);
|
||||
}
|
||||
235
test/tests/eval_full_multi_test.cpp
Normal file
235
test/tests/eval_full_multi_test.cpp
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "helpers/eval_common_multi_data.hpp"
|
||||
|
||||
template <typename T>
|
||||
struct EvalFullMultiTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
using input_type = typename std::tuple_element_t<0, T>;
|
||||
using output_type0 = typename std::tuple_element_t<1, T>;
|
||||
using output_type1 = typename std::tuple_element_t<2, T>;
|
||||
using output_type2 = typename std::tuple_element_t<3, T>;
|
||||
using output_type3 = typename std::tuple_element_t<4, T>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type0, output_type1, output_type2, output_type3>;
|
||||
|
||||
protected:
|
||||
EvalFullMultiTest()
|
||||
: params{std::get<std::vector<T>>(allParams)},
|
||||
range{std::size_t(1) << dpf::utils::bitlength_of_v<input_type>},
|
||||
zero_output0{from_integral_type_output0(0)},
|
||||
zero_output1{from_integral_type_output1(0)},
|
||||
zero_output2{from_integral_type_output2(0)},
|
||||
zero_output3{from_integral_type_output3(0)}
|
||||
{ }
|
||||
|
||||
void SetUp() override
|
||||
{ }
|
||||
|
||||
void TearDown() override
|
||||
{ }
|
||||
|
||||
template <typename IterableT0, typename IterableT1>
|
||||
void assert_wrapper(const input_type & x, const output_type0 & y0,
|
||||
const output_type1 & y1, const output_type2 & y2, const output_type3 & y3,
|
||||
IterableT0 & iter0, IterableT1 & iter1)
|
||||
{
|
||||
auto zip0 = dpf::tuple_as_zip(iter0);
|
||||
auto zip1 = dpf::tuple_as_zip(iter1);
|
||||
auto it0 = std::cbegin(zip0);
|
||||
auto it1 = std::cbegin(zip1);
|
||||
input_type cur = std::numeric_limits<input_type>::min();
|
||||
for (std::size_t i = 0; i < range; ++i, cur = next_domain_point(cur), ++it0, ++it1)
|
||||
{
|
||||
if (cur == x)
|
||||
{
|
||||
ASSERT_EQ(recon(std::get<0>(*it0), std::get<0>(*it1)), y0);
|
||||
ASSERT_EQ(recon(std::get<1>(*it0), std::get<1>(*it1)), y1);
|
||||
ASSERT_EQ(recon(std::get<2>(*it0), std::get<2>(*it1)), y2);
|
||||
ASSERT_EQ(recon(std::get<3>(*it0), std::get<3>(*it1)), y3);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(recon(std::get<0>(*it0), std::get<0>(*it1)), zero_output0);
|
||||
ASSERT_EQ(recon(std::get<1>(*it0), std::get<1>(*it1)), zero_output1);
|
||||
ASSERT_EQ(recon(std::get<2>(*it0), std::get<2>(*it1)), zero_output2);
|
||||
ASSERT_EQ(recon(std::get<3>(*it0), std::get<3>(*it1)), zero_output3);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(zip0));
|
||||
ASSERT_EQ(it1, std::end(zip1));
|
||||
}
|
||||
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output0 = dpf::utils::make_from_integral_value<output_type0>{};
|
||||
static constexpr auto from_integral_type_output1 = dpf::utils::make_from_integral_value<output_type1>{};
|
||||
static constexpr auto from_integral_type_output2 = dpf::utils::make_from_integral_value<output_type2>{};
|
||||
static constexpr auto from_integral_type_output3 = dpf::utils::make_from_integral_value<output_type3>{};
|
||||
|
||||
std::vector<T> params;
|
||||
std::size_t range;
|
||||
output_type0 zero_output0;
|
||||
output_type1 zero_output1;
|
||||
output_type2 zero_output2;
|
||||
output_type3 zero_output3;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EvalFullMultiTest);
|
||||
|
||||
TYPED_TEST_P(EvalFullMultiTest, Basic)
|
||||
{
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_full<0, 1, 2, 3>(dpf0);
|
||||
auto [buf1, iter1] = dpf::eval_full<0, 1, 2, 3>(dpf1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullMultiTest, Outbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_full<dpf_type, 0, 1, 2, 3>(),
|
||||
buf1 = dpf::make_output_buffer_for_full<dpf_type, 0, 1, 2, 3>();
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_full<0, 1, 2, 3>(dpf0, buf0),
|
||||
iter1 = dpf::eval_full<0, 1, 2, 3>(dpf1, buf1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullMultiTest, BasicFullMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_full<0, 1, 2, 3>(dpf0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_full<0, 1, 2, 3>(dpf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullMultiTest, FullTreeFullMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_full_tree_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_full_tree_full_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_full<0, 1, 2, 3>(dpf0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_full<0, 1, 2, 3>(dpf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullMultiTest, BasicFullMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_full<dpf_type, 0, 1, 2, 3>(),
|
||||
buf1 = dpf::make_output_buffer_for_full<dpf_type, 0, 1, 2, 3>();
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_full<0, 1, 2, 3>(dpf0, buf0, memo0),
|
||||
iter1 = dpf::eval_full<0, 1, 2, 3>(dpf1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullMultiTest, FullTreeFullMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_full<dpf_type, 0, 1, 2, 3>(),
|
||||
buf1 = dpf::make_output_buffer_for_full<dpf_type, 0, 1, 2, 3>();
|
||||
auto memo0 = dpf::make_full_tree_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_full_tree_full_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_full<0, 1, 2, 3>(dpf0, buf0, memo0),
|
||||
iter1 = dpf::eval_full<0, 1, 2, 3>(dpf1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EvalFullMultiTest,
|
||||
Basic,
|
||||
Outbuf,
|
||||
BasicFullMemoizer,
|
||||
FullTreeFullMemoizer,
|
||||
BasicFullMemoizerOutbuf,
|
||||
FullTreeFullMemoizerOutbuf);
|
||||
using Types = testing::Types
|
||||
<
|
||||
// base test
|
||||
test_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
test_type<int16_t, uint64_t>,
|
||||
test_type<uint8_t, uint64_t>,
|
||||
test_type<dpf::bitstring<10>, uint64_t>,
|
||||
test_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
test_type<dpf::modint<10>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
test_type<uint16_t, int64_t>,
|
||||
test_type<uint16_t, uint8_t>,
|
||||
test_type<uint16_t, simde_int128>,
|
||||
test_type<uint16_t, simde_uint128>,
|
||||
test_type<uint16_t, dpf::bit>,
|
||||
test_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
test_type<uint16_t, dpf::bitstring<150>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
test_type<custom_input_type, uint64_t>,
|
||||
test_type<uint16_t, custom_output_type_small>,
|
||||
test_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
test_type<uint16_t, custom_output_type_large_xor>,
|
||||
|
||||
// distinct output types
|
||||
multi_test_type<uint16_t, uint32_t, dpf::xor_wrapper<uint32_t>, dpf::bitstring<20, uint8_t>, dpf::bitstring<32>>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(EvalFullMultiTestInstantiation, EvalFullMultiTest, Types);
|
||||
209
test/tests/eval_full_test.cpp
Normal file
209
test/tests/eval_full_test.cpp
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include "helpers/eval_common_data.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
struct EvalFullTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
using input_type = typename std::tuple_element_t<0, T>;
|
||||
using output_type = typename std::tuple_element_t<1, T>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
|
||||
protected:
|
||||
EvalFullTest()
|
||||
: params{std::get<std::vector<T>>(allParams)},
|
||||
range{std::size_t(1) << dpf::utils::bitlength_of_v<input_type>},
|
||||
zero_output{from_integral_type_output(0)}
|
||||
{ }
|
||||
|
||||
void SetUp() override
|
||||
{ }
|
||||
|
||||
void TearDown() override
|
||||
{ }
|
||||
|
||||
template <typename IterableT0, typename IterableT1>
|
||||
void assert_wrapper(const input_type & x, const output_type & y,
|
||||
const IterableT0 & iter0, const IterableT1 & iter1)
|
||||
{
|
||||
auto it0 = std::cbegin(iter0);
|
||||
auto it1 = std::cbegin(iter1);
|
||||
input_type cur = std::numeric_limits<input_type>::min();
|
||||
for (std::size_t i = 0; i < range; ++i, cur = next_domain_point(cur), ++it0, ++it1)
|
||||
{
|
||||
if (cur == x)
|
||||
{
|
||||
ASSERT_EQ(recon(*it0, *it1), y);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(recon(*it0, *it1), zero_output);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(iter0));
|
||||
ASSERT_EQ(it1, std::end(iter1));
|
||||
}
|
||||
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output = dpf::utils::make_from_integral_value<output_type>{};
|
||||
|
||||
std::vector<T> params;
|
||||
std::size_t range;
|
||||
output_type zero_output;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EvalFullTest);
|
||||
|
||||
TYPED_TEST_P(EvalFullTest, Basic)
|
||||
{
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_full(dpf0);
|
||||
auto [buf1, iter1] = dpf::eval_full(dpf1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullTest, Outbuf)
|
||||
{
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto buf0 = dpf::make_output_buffer_for_full(dpf0),
|
||||
buf1 = dpf::make_output_buffer_for_full(dpf1);
|
||||
auto iter0 = dpf::eval_full(dpf0, buf0),
|
||||
iter1 = dpf::eval_full(dpf1, buf1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullTest, BasicFullMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_full(dpf0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_full(dpf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullTest, FullTreeFullMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_full_tree_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_full_tree_full_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_full(dpf0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_full(dpf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullTest, BasicFullMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_full<dpf_type>(),
|
||||
buf1 = dpf::make_output_buffer_for_full<dpf_type>();
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_full(dpf0, buf0, memo0),
|
||||
iter1 = dpf::eval_full(dpf1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalFullTest, FullTreeFullMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_full<dpf_type>(),
|
||||
buf1 = dpf::make_output_buffer_for_full<dpf_type>();
|
||||
auto memo0 = dpf::make_full_tree_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_full_tree_full_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_full(dpf0, buf0, memo0),
|
||||
iter1 = dpf::eval_full(dpf1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EvalFullTest,
|
||||
Basic,
|
||||
Outbuf,
|
||||
BasicFullMemoizer,
|
||||
FullTreeFullMemoizer,
|
||||
BasicFullMemoizerOutbuf,
|
||||
FullTreeFullMemoizerOutbuf);
|
||||
using Types = testing::Types
|
||||
<
|
||||
// base test
|
||||
test_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
test_type<int16_t, uint64_t>,
|
||||
test_type<uint8_t, uint64_t>,
|
||||
test_type<dpf::bitstring<10>, uint64_t>,
|
||||
test_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
test_type<dpf::modint<10>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
test_type<uint16_t, int64_t>,
|
||||
test_type<uint16_t, uint8_t>,
|
||||
test_type<uint16_t, simde_int128>,
|
||||
test_type<uint16_t, simde_uint128>,
|
||||
test_type<uint16_t, dpf::bit>,
|
||||
test_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
test_type<uint16_t, dpf::bitstring<150>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
test_type<custom_input_type, uint64_t>,
|
||||
test_type<uint16_t, custom_output_type_small>,
|
||||
test_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
test_type<uint16_t, custom_output_type_large_xor>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(EvalFullTestInstantiation, EvalFullTest, Types);
|
||||
302
test/tests/eval_interval_multi_test.cpp
Normal file
302
test/tests/eval_interval_multi_test.cpp
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "helpers/eval_common_multi_data.hpp"
|
||||
|
||||
template <typename T>
|
||||
struct EvalIntervalMultiTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
using input_type = typename std::tuple_element_t<0, T>;
|
||||
using output_type0 = typename std::tuple_element_t<1, T>;
|
||||
using output_type1 = typename std::tuple_element_t<2, T>;
|
||||
using output_type2 = typename std::tuple_element_t<3, T>;
|
||||
using output_type3 = typename std::tuple_element_t<4, T>;
|
||||
using integral_type = dpf::utils::integral_type_from_bitlength_t<dpf::utils::bitlength_of_v<input_type>>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type0, output_type1, output_type2, output_type3>;
|
||||
|
||||
protected:
|
||||
EvalIntervalMultiTest()
|
||||
: params{std::get<std::vector<T>>(allParams)},
|
||||
range{(std::size_t(1) << std::min(dpf::utils::bitlength_of_v<input_type>, std::size_t(10))-1)-1},
|
||||
zero_output0{from_integral_type_output0(0)},
|
||||
zero_output1{from_integral_type_output1(0)},
|
||||
zero_output2{from_integral_type_output2(0)},
|
||||
zero_output3{from_integral_type_output3(0)},
|
||||
max_from_to{get_max_from_to()}
|
||||
{ }
|
||||
|
||||
void SetUp() override
|
||||
{ }
|
||||
|
||||
void TearDown() override
|
||||
{ }
|
||||
|
||||
std::pair<input_type, input_type> get_from_to(const input_type & x)
|
||||
{
|
||||
integral_type x_int = to_integral_type(x),
|
||||
min_int = to_integral_type(std::numeric_limits<input_type>::min()),
|
||||
max_int = to_integral_type(std::numeric_limits<input_type>::max()),
|
||||
from_int, to_int;
|
||||
// set [from_int, to_int] to be centered around x_int if possible
|
||||
// use [min_int, min_int+2*range] or [max_int-2*range, max_int] as needed otherwise
|
||||
// range is selected to be at most 1 less than half the maximum range for input_type
|
||||
// this ensures there are no overflow issues
|
||||
// for signed integral types, since the MSB is internally flipped,
|
||||
// needed additional check that x_int was in the correct range for the given
|
||||
// conditionals (note that these added checks are always try for unsigned types)
|
||||
if (x_int < min_int + range && x_int >= min_int)
|
||||
{
|
||||
from_int = min_int;
|
||||
to_int = min_int + (range << 1);
|
||||
}
|
||||
else if (x_int > max_int - range && x_int <= max_int)
|
||||
{
|
||||
from_int = max_int - (range << 1);
|
||||
to_int = max_int;
|
||||
}
|
||||
else
|
||||
{
|
||||
from_int = x_int - range;
|
||||
to_int = x_int + range;
|
||||
}
|
||||
return std::make_pair(from_integral_type(from_int), from_integral_type(to_int));
|
||||
}
|
||||
|
||||
template <typename IterableT0, typename IterableT1>
|
||||
void assert_wrapper(const input_type & x, const output_type0 & y0,
|
||||
const output_type1 & y1, const output_type2 & y2, const output_type3 & y3,
|
||||
input_type cur, IterableT0 & iter0, IterableT1 & iter1)
|
||||
{
|
||||
auto zip0 = dpf::tuple_as_zip(iter0);
|
||||
auto zip1 = dpf::tuple_as_zip(iter1);
|
||||
auto it0 = std::begin(zip0);
|
||||
auto it1 = std::begin(zip1);
|
||||
for (std::size_t i = 0; i <= range<<1; ++i, cur = next_domain_point(cur), ++it0, ++it1)
|
||||
{
|
||||
if (cur == x)
|
||||
{
|
||||
ASSERT_EQ(recon(std::get<0>(*it0), std::get<0>(*it1)), y0);
|
||||
ASSERT_EQ(recon(std::get<1>(*it0), std::get<1>(*it1)), y1);
|
||||
ASSERT_EQ(recon(std::get<2>(*it0), std::get<2>(*it1)), y2);
|
||||
ASSERT_EQ(recon(std::get<3>(*it0), std::get<3>(*it1)), y3);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(recon(std::get<0>(*it0), std::get<0>(*it1)), zero_output0);
|
||||
ASSERT_EQ(recon(std::get<1>(*it0), std::get<1>(*it1)), zero_output1);
|
||||
ASSERT_EQ(recon(std::get<2>(*it0), std::get<2>(*it1)), zero_output2);
|
||||
ASSERT_EQ(recon(std::get<3>(*it0), std::get<3>(*it1)), zero_output3);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(zip0));
|
||||
ASSERT_EQ(it1, std::end(zip1));
|
||||
}
|
||||
|
||||
// calculate maximum node difference between from and to
|
||||
// this allows the memoizers to be created with the correct size in advance
|
||||
std::pair<input_type, input_type> get_max_from_to()
|
||||
{
|
||||
input_type max_from, max_to;
|
||||
std::size_t max_range = 0;
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
std::size_t cur_range = dpf::utils::get_nodes_in_interval<dpf_type>(from, to);
|
||||
if (cur_range > max_range)
|
||||
{
|
||||
max_range = cur_range;
|
||||
max_from = from;
|
||||
max_to = to;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(max_from, max_to);
|
||||
}
|
||||
|
||||
static constexpr auto to_integral_type = dpf::utils::to_integral_type<input_type>{};
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output0 = dpf::utils::make_from_integral_value<output_type0>{};
|
||||
static constexpr auto from_integral_type_output1 = dpf::utils::make_from_integral_value<output_type1>{};
|
||||
static constexpr auto from_integral_type_output2 = dpf::utils::make_from_integral_value<output_type2>{};
|
||||
static constexpr auto from_integral_type_output3 = dpf::utils::make_from_integral_value<output_type3>{};
|
||||
|
||||
std::vector<T> params;
|
||||
std::size_t range;
|
||||
output_type0 zero_output0;
|
||||
output_type1 zero_output1;
|
||||
output_type2 zero_output2;
|
||||
output_type3 zero_output3;
|
||||
std::pair<input_type, input_type> max_from_to;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EvalIntervalMultiTest);
|
||||
|
||||
TYPED_TEST_P(EvalIntervalMultiTest, Basic)
|
||||
{
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto [buf0, iter0] = dpf::eval_interval<0, 1, 2, 3>(dpf0, from, to);
|
||||
auto [buf1, iter1] = dpf::eval_interval<0, 1, 2, 3>(dpf1, from, to);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalMultiTest, Outbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_interval<dpf_type, 0, 1, 2, 3>(this->max_from_to.first, this->max_from_to.second),
|
||||
buf1 = dpf::make_output_buffer_for_interval<dpf_type, 0, 1, 2, 3>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto iter0 = dpf::eval_interval<0, 1, 2, 3>(dpf0, from, to, buf0),
|
||||
iter1 = dpf::eval_interval<0, 1, 2, 3>(dpf1, from, to, buf1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalMultiTest, BasicIntervalMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_basic_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second),
|
||||
memo1 = dpf::make_basic_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto [buf0, iter0] = dpf::eval_interval<0, 1, 2, 3>(dpf0, from, to, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_interval<0, 1, 2, 3>(dpf1, from, to, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalMultiTest, FullTreeIntervalMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_full_tree_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second),
|
||||
memo1 = dpf::make_full_tree_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto [buf0, iter0] = dpf::eval_interval<0, 1, 2, 3>(dpf0, from, to, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_interval<0, 1, 2, 3>(dpf1, from, to, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalMultiTest, BasicIntervalMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_interval<dpf_type, 0, 1, 2, 3>(this->max_from_to.first, this->max_from_to.second),
|
||||
buf1 = dpf::make_output_buffer_for_interval<dpf_type, 0, 1, 2, 3>(this->max_from_to.first, this->max_from_to.second);
|
||||
auto memo0 = dpf::make_basic_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second),
|
||||
memo1 = dpf::make_basic_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto iter0 = dpf::eval_interval<0, 1, 2, 3>(dpf0, from, to, buf0, memo0),
|
||||
iter1 = dpf::eval_interval<0, 1, 2, 3>(dpf1, from, to, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalMultiTest, FullTreeIntervalMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_interval<dpf_type, 0, 1, 2, 3>(this->max_from_to.first, this->max_from_to.second),
|
||||
buf1 = dpf::make_output_buffer_for_interval<dpf_type, 0, 1, 2, 3>(this->max_from_to.first, this->max_from_to.second);
|
||||
auto memo0 = dpf::make_full_tree_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second),
|
||||
memo1 = dpf::make_full_tree_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto iter0 = dpf::eval_interval<0, 1, 2, 3>(dpf0, from, to, buf0, memo0),
|
||||
iter1 = dpf::eval_interval<0, 1, 2, 3>(dpf1, from, to, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EvalIntervalMultiTest,
|
||||
Basic,
|
||||
Outbuf,
|
||||
BasicIntervalMemoizer,
|
||||
FullTreeIntervalMemoizer,
|
||||
BasicIntervalMemoizerOutbuf,
|
||||
FullTreeIntervalMemoizerOutbuf);
|
||||
using Types = testing::Types
|
||||
<
|
||||
// base test
|
||||
test_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
test_type<int16_t, uint64_t>,
|
||||
test_type<uint8_t, uint64_t>,
|
||||
test_type<uint64_t, uint64_t>,
|
||||
test_type<simde_int128, uint64_t>,
|
||||
test_type<simde_uint128, uint64_t>,
|
||||
test_type<dpf::bitstring<10>, uint64_t>,
|
||||
test_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
test_type<dpf::modint<10>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
test_type<uint16_t, int64_t>,
|
||||
test_type<uint16_t, uint8_t>,
|
||||
test_type<uint16_t, simde_int128>,
|
||||
test_type<uint16_t, simde_uint128>,
|
||||
test_type<uint16_t, dpf::bit>,
|
||||
test_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
test_type<uint16_t, dpf::bitstring<150>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
test_type<custom_input_type, uint64_t>,
|
||||
test_type<uint16_t, custom_output_type_small>,
|
||||
test_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
test_type<uint16_t, custom_output_type_large_xor>,
|
||||
|
||||
// distinct output types
|
||||
multi_test_type<uint16_t, uint32_t, dpf::xor_wrapper<uint32_t>, dpf::bitstring<20, uint8_t>, dpf::bitstring<32>>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(EvalIntervalMultiTestInstantiation, EvalIntervalMultiTest, Types);
|
||||
275
test/tests/eval_interval_test.cpp
Normal file
275
test/tests/eval_interval_test.cpp
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include "helpers/eval_common_data.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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
struct EvalIntervalTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
using input_type = typename std::tuple_element_t<0, T>;
|
||||
using output_type = typename std::tuple_element_t<1, T>;
|
||||
using integral_type = dpf::utils::integral_type_from_bitlength_t<dpf::utils::bitlength_of_v<input_type>>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
|
||||
protected:
|
||||
EvalIntervalTest()
|
||||
: params{std::get<std::vector<T>>(allParams)},
|
||||
range{(std::size_t(1) << std::min(dpf::utils::bitlength_of_v<input_type>, std::size_t(10))-1)-1},
|
||||
zero_output{from_integral_type_output(0)},
|
||||
max_from_to{get_max_from_to()}
|
||||
{ }
|
||||
|
||||
void SetUp() override
|
||||
{ }
|
||||
|
||||
void TearDown() override
|
||||
{ }
|
||||
|
||||
std::pair<input_type, input_type> get_from_to(const input_type & x)
|
||||
{
|
||||
integral_type x_int = to_integral_type(x),
|
||||
min_int = to_integral_type(std::numeric_limits<input_type>::min()),
|
||||
max_int = to_integral_type(std::numeric_limits<input_type>::max()),
|
||||
from_int, to_int;
|
||||
// set [from_int, to_int] to be centered around x_int if possible
|
||||
// use [min_int, min_int+2*range] or [max_int-2*range, max_int] as needed otherwise
|
||||
// range is selected to be at most 1 less than half the maximum range for input_type
|
||||
// this ensures there are no overflow issues
|
||||
// for signed integral types, since the MSB is internally flipped,
|
||||
// needed additional check that x_int was in the correct range for the given
|
||||
// conditionals (note that these added checks are always try for unsigned types)
|
||||
if (x_int < min_int + range && x_int >= min_int)
|
||||
{
|
||||
from_int = min_int;
|
||||
to_int = min_int + (range << 1);
|
||||
}
|
||||
else if (x_int > max_int - range && x_int <= max_int)
|
||||
{
|
||||
from_int = max_int - (range << 1);
|
||||
to_int = max_int;
|
||||
}
|
||||
else
|
||||
{
|
||||
from_int = x_int - range;
|
||||
to_int = x_int + range;
|
||||
}
|
||||
return std::make_pair(from_integral_type(from_int), from_integral_type(to_int));
|
||||
}
|
||||
|
||||
template <typename IterableT0, typename IterableT1>
|
||||
void assert_wrapper(const input_type & x, const output_type & y,
|
||||
input_type cur, const IterableT0 & iter0, const IterableT1 & iter1)
|
||||
{
|
||||
auto it0 = std::begin(iter0);
|
||||
auto it1 = std::begin(iter1);
|
||||
for (std::size_t i = 0; i <= range<<1; ++i, cur = next_domain_point(cur), ++it0, ++it1)
|
||||
{
|
||||
if (cur == x)
|
||||
{
|
||||
ASSERT_EQ(recon(*it0, *it1), y);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(recon(*it0, *it1), zero_output);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(iter0));
|
||||
ASSERT_EQ(it1, std::end(iter1));
|
||||
}
|
||||
|
||||
// calculate maximum node difference between from and to
|
||||
// this allows the memoizers to be created with the correct size in advance
|
||||
std::pair<input_type, input_type> get_max_from_to()
|
||||
{
|
||||
input_type max_from, max_to;
|
||||
std::size_t max_range = 0;
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
std::size_t cur_range = dpf::utils::get_nodes_in_interval<dpf_type>(from, to);
|
||||
if (cur_range > max_range)
|
||||
{
|
||||
max_range = cur_range;
|
||||
max_from = from;
|
||||
max_to = to;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(max_from, max_to);
|
||||
}
|
||||
|
||||
static constexpr auto to_integral_type = dpf::utils::to_integral_type<input_type>{};
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output = dpf::utils::make_from_integral_value<output_type>{};
|
||||
|
||||
std::vector<T> params;
|
||||
std::size_t range;
|
||||
output_type zero_output;
|
||||
std::pair<input_type, input_type> max_from_to;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EvalIntervalTest);
|
||||
|
||||
TYPED_TEST_P(EvalIntervalTest, Basic)
|
||||
{
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto [buf0, iter0] = dpf::eval_interval(dpf0, from, to);
|
||||
auto [buf1, iter1] = dpf::eval_interval(dpf1, from, to);
|
||||
|
||||
this->assert_wrapper(x, y, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalTest, Outbuf)
|
||||
{
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto buf0 = dpf::make_output_buffer_for_interval(dpf0, this->max_from_to.first, this->max_from_to.second),
|
||||
buf1 = dpf::make_output_buffer_for_interval(dpf1, this->max_from_to.first, this->max_from_to.second);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto iter0 = dpf::eval_interval(dpf0, from, to, buf0),
|
||||
iter1 = dpf::eval_interval(dpf1, from, to, buf1);
|
||||
|
||||
this->assert_wrapper(x, y, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalTest, BasicIntervalMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_basic_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second),
|
||||
memo1 = dpf::make_basic_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto [buf0, iter0] = dpf::eval_interval(dpf0, from, to, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_interval(dpf1, from, to, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalTest, FullTreeIntervalMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_full_tree_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second),
|
||||
memo1 = dpf::make_full_tree_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto [buf0, iter0] = dpf::eval_interval(dpf0, from, to, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_interval(dpf1, from, to, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalTest, BasicIntervalMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_basic_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second),
|
||||
memo1 = dpf::make_basic_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto buf0 = dpf::make_output_buffer_for_interval(dpf0, this->max_from_to.first, this->max_from_to.second),
|
||||
buf1 = dpf::make_output_buffer_for_interval(dpf1, this->max_from_to.first, this->max_from_to.second);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto iter0 = dpf::eval_interval(dpf0, from, to, buf0, memo0),
|
||||
iter1 = dpf::eval_interval(dpf1, from, to, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalIntervalTest, FullTreeIntervalMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_full_tree_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second),
|
||||
memo1 = dpf::make_full_tree_interval_memoizer<dpf_type>(this->max_from_to.first, this->max_from_to.second);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto buf0 = dpf::make_output_buffer_for_interval(dpf0, this->max_from_to.first, this->max_from_to.second),
|
||||
buf1 = dpf::make_output_buffer_for_interval(dpf1, this->max_from_to.first, this->max_from_to.second);
|
||||
auto [from, to] = this->get_from_to(x);
|
||||
auto iter0 = dpf::eval_interval(dpf0, from, to, buf0, memo0),
|
||||
iter1 = dpf::eval_interval(dpf1, from, to, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, from, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EvalIntervalTest,
|
||||
Basic,
|
||||
Outbuf,
|
||||
BasicIntervalMemoizer,
|
||||
FullTreeIntervalMemoizer,
|
||||
BasicIntervalMemoizerOutbuf,
|
||||
FullTreeIntervalMemoizerOutbuf);
|
||||
using Types = testing::Types
|
||||
<
|
||||
// base test
|
||||
test_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
test_type<int16_t, uint64_t>,
|
||||
test_type<uint8_t, uint64_t>,
|
||||
test_type<uint64_t, uint64_t>,
|
||||
test_type<simde_int128, uint64_t>,
|
||||
test_type<simde_uint128, uint64_t>,
|
||||
test_type<dpf::bitstring<10>, uint64_t>,
|
||||
test_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
test_type<dpf::modint<10>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
test_type<uint16_t, int64_t>,
|
||||
test_type<uint16_t, uint8_t>,
|
||||
test_type<uint16_t, simde_int128>,
|
||||
test_type<uint16_t, simde_uint128>,
|
||||
test_type<uint16_t, dpf::bit>,
|
||||
test_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
test_type<uint16_t, dpf::bitstring<150>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
test_type<custom_input_type, uint64_t>,
|
||||
test_type<uint16_t, custom_output_type_small>,
|
||||
test_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
test_type<uint16_t, custom_output_type_large_xor>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(EvalIntervalTestInstantiation, EvalIntervalTest, Types);
|
||||
235
test/tests/eval_point_multi_test.cpp
Normal file
235
test/tests/eval_point_multi_test.cpp
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "helpers/eval_common_multi_data.hpp"
|
||||
|
||||
template <typename T>
|
||||
struct EvalPointMultiTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
using input_type = typename std::tuple_element_t<0, T>;
|
||||
using output_type0 = typename std::tuple_element_t<1, T>;
|
||||
using output_type1 = typename std::tuple_element_t<2, T>;
|
||||
using output_type2 = typename std::tuple_element_t<3, T>;
|
||||
using output_type3 = typename std::tuple_element_t<4, T>;
|
||||
using integral_type = dpf::utils::integral_type_from_bitlength_t<dpf::utils::bitlength_of_v<input_type>>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type0, output_type1, output_type2, output_type3>;
|
||||
|
||||
protected:
|
||||
EvalPointMultiTest()
|
||||
: params{std::get<std::vector<T>>(allParams)},
|
||||
range{(std::size_t(1) << std::min(dpf::utils::bitlength_of_v<input_type>, std::size_t(10))-1)-1},
|
||||
zero_output0{from_integral_type_output0(0)},
|
||||
zero_output1{from_integral_type_output1(0)},
|
||||
zero_output2{from_integral_type_output2(0)},
|
||||
zero_output3{from_integral_type_output3(0)}
|
||||
{ }
|
||||
|
||||
void SetUp() override
|
||||
{ }
|
||||
|
||||
void TearDown() override
|
||||
{ }
|
||||
|
||||
input_type get_start(const input_type & x)
|
||||
{
|
||||
integral_type x_int = to_integral_type(x),
|
||||
min_int = to_integral_type(std::numeric_limits<input_type>::min()),
|
||||
max_int = to_integral_type(std::numeric_limits<input_type>::max()),
|
||||
start_int;
|
||||
// set start_int so that the tested range is centered around x_int if possible
|
||||
// use start_int = min_int if x_int smaller than min_int+range
|
||||
// or start_int = max_int-2*range if x_int larger than max_int-range
|
||||
// range is selected to be at most 1 less than half the maximum range for input_type
|
||||
// this ensures there are no overflow issues
|
||||
// for signed integral types, since the MSB is internally flipped,
|
||||
// needed additional check that x_int was in the correct range for the given
|
||||
// conditionals (note that these added checks are always try for unsigned types)
|
||||
if (x_int < min_int + range && x_int >= min_int)
|
||||
{
|
||||
start_int = min_int;
|
||||
}
|
||||
else if (x_int > max_int - range && x_int <= max_int)
|
||||
{
|
||||
start_int = max_int - (range << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
start_int = x_int - range;
|
||||
}
|
||||
return from_integral_type(start_int);
|
||||
}
|
||||
|
||||
template <typename UnaryFunction0, typename UnaryFunction1>
|
||||
void assert_wrapper(const input_type & x, const output_type0 & y0,
|
||||
const output_type1 & y1, const output_type2 & y2, const output_type3 & y3,
|
||||
UnaryFunction0 f0, UnaryFunction1 f1)
|
||||
{
|
||||
input_type cur = get_start(x);
|
||||
for (std::size_t i = 0; i <= range<<1; ++i, cur = next_domain_point(cur))
|
||||
{
|
||||
auto out0 = f0(cur),
|
||||
out1 = f1(cur);
|
||||
if (cur == x)
|
||||
{
|
||||
ASSERT_EQ(recon(std::get<0>(out0), std::get<0>(out1)), y0);
|
||||
ASSERT_EQ(recon(std::get<1>(out0), std::get<1>(out1)), y1);
|
||||
ASSERT_EQ(recon(std::get<2>(out0), std::get<2>(out1)), y2);
|
||||
ASSERT_EQ(recon(std::get<3>(out0), std::get<3>(out1)), y3);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(recon(std::get<0>(out0), std::get<0>(out1)), zero_output0);
|
||||
ASSERT_EQ(recon(std::get<1>(out0), std::get<1>(out1)), zero_output1);
|
||||
ASSERT_EQ(recon(std::get<2>(out0), std::get<2>(out1)), zero_output2);
|
||||
ASSERT_EQ(recon(std::get<3>(out0), std::get<3>(out1)), zero_output3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr auto to_integral_type = dpf::utils::to_integral_type<input_type>{};
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output0 = dpf::utils::make_from_integral_value<output_type0>{};
|
||||
static constexpr auto from_integral_type_output1 = dpf::utils::make_from_integral_value<output_type1>{};
|
||||
static constexpr auto from_integral_type_output2 = dpf::utils::make_from_integral_value<output_type2>{};
|
||||
static constexpr auto from_integral_type_output3 = dpf::utils::make_from_integral_value<output_type3>{};
|
||||
|
||||
std::vector<T> params;
|
||||
std::size_t range;
|
||||
output_type0 zero_output0;
|
||||
output_type1 zero_output1;
|
||||
output_type2 zero_output2;
|
||||
output_type3 zero_output3;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EvalPointMultiTest);
|
||||
|
||||
TYPED_TEST_P(EvalPointMultiTest, Basic)
|
||||
{
|
||||
using input_type = typename TestFixture::input_type;
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3,
|
||||
[&dpf0](input_type cur)
|
||||
{
|
||||
return dpf::eval_point<0, 1, 2, 3>(dpf0, cur);
|
||||
},
|
||||
[&dpf1](input_type cur)
|
||||
{
|
||||
return dpf::eval_point<0, 1, 2, 3>(dpf1, cur);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalPointMultiTest, BasicPathMemoizer)
|
||||
{
|
||||
using input_type = typename TestFixture::input_type;
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_basic_path_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_path_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3,
|
||||
[&dpf0, &memo0](input_type cur)
|
||||
{
|
||||
return dpf::eval_point<0, 1, 2, 3>(dpf0, cur, memo0);
|
||||
},
|
||||
[&dpf1, &memo1](input_type cur)
|
||||
{
|
||||
return dpf::eval_point<0, 1, 2, 3>(dpf1, cur, memo1);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalPointMultiTest, NonmemoizingPathMemoizer)
|
||||
{
|
||||
using input_type = typename TestFixture::input_type;
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto memo0 = dpf::make_nonmemoizing_path_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_nonmemoizing_path_memoizer<dpf_type>();
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3,
|
||||
[&dpf0, &memo0](input_type cur)
|
||||
{
|
||||
return dpf::eval_point<0, 1, 2, 3>(dpf0, cur, memo0);
|
||||
},
|
||||
[&dpf1, &memo1](input_type cur)
|
||||
{
|
||||
return dpf::eval_point<0, 1, 2, 3>(dpf1, cur, memo1);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EvalPointMultiTest,
|
||||
Basic,
|
||||
BasicPathMemoizer,
|
||||
NonmemoizingPathMemoizer);
|
||||
using Types = testing::Types
|
||||
<
|
||||
// base test
|
||||
test_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
test_type<int16_t, uint64_t>,
|
||||
test_type<uint8_t, uint64_t>,
|
||||
test_type<uint64_t, uint64_t>,
|
||||
test_type<simde_int128, uint64_t>,
|
||||
test_type<simde_uint128, uint64_t>,
|
||||
test_type<dpf::bitstring<10>, uint64_t>,
|
||||
test_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
test_type<dpf::modint<10>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
test_type<uint16_t, int64_t>,
|
||||
test_type<uint16_t, uint8_t>,
|
||||
test_type<uint16_t, simde_int128>,
|
||||
test_type<uint16_t, simde_uint128>,
|
||||
test_type<uint16_t, dpf::bit>,
|
||||
test_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
test_type<uint16_t, dpf::bitstring<150>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
test_type<custom_input_type, uint64_t>,
|
||||
test_type<uint16_t, custom_output_type_small>,
|
||||
test_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
test_type<uint16_t, custom_output_type_large_xor>,
|
||||
|
||||
// distinct output types
|
||||
multi_test_type<uint16_t, uint32_t, dpf::xor_wrapper<uint32_t>, dpf::bitstring<20, uint8_t>, dpf::bitstring<32>>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(EvalPointMultiTestInstantiation, EvalPointMultiTest, Types);
|
||||
216
test/tests/eval_point_test.cpp
Normal file
216
test/tests/eval_point_test.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include "helpers/eval_common_data.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
struct EvalPointTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
using input_type = typename std::tuple_element_t<0, T>;
|
||||
using output_type = typename std::tuple_element_t<1, T>;
|
||||
using integral_type = dpf::utils::integral_type_from_bitlength_t<dpf::utils::bitlength_of_v<input_type>>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
|
||||
protected:
|
||||
EvalPointTest()
|
||||
: params{std::get<std::vector<T>>(allParams)},
|
||||
range{(std::size_t(1) << std::min(dpf::utils::bitlength_of_v<input_type>, std::size_t(10))-1)-1},
|
||||
zero_output{from_integral_type_output(0)}
|
||||
{ }
|
||||
|
||||
void SetUp() override
|
||||
{ }
|
||||
|
||||
void TearDown() override
|
||||
{ }
|
||||
|
||||
input_type get_start(const input_type & x)
|
||||
{
|
||||
integral_type x_int = to_integral_type(x),
|
||||
min_int = to_integral_type(std::numeric_limits<input_type>::min()),
|
||||
max_int = to_integral_type(std::numeric_limits<input_type>::max()),
|
||||
start_int;
|
||||
// set start_int so that the tested range is centered around x_int if possible
|
||||
// use start_int = min_int if x_int smaller than min_int+range
|
||||
// or start_int = max_int-2*range if x_int larger than max_int-range
|
||||
// range is selected to be at most 1 less than half the maximum range for input_type
|
||||
// this ensures there are no overflow issues
|
||||
// for signed integral types, since the MSB is internally flipped,
|
||||
// needed additional check that x_int was in the correct range for the given
|
||||
// conditionals (note that these added checks are always try for unsigned types)
|
||||
if (x_int < min_int + range && x_int >= min_int)
|
||||
{
|
||||
start_int = min_int;
|
||||
}
|
||||
else if (x_int > max_int - range && x_int <= max_int)
|
||||
{
|
||||
start_int = max_int - (range << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
start_int = x_int - range;
|
||||
}
|
||||
return from_integral_type(start_int);
|
||||
}
|
||||
|
||||
template <typename UnaryFunction0, typename UnaryFunction1>
|
||||
void assert_wrapper(const input_type & x, const output_type & y,
|
||||
UnaryFunction0 f0, UnaryFunction1 f1)
|
||||
{
|
||||
input_type cur = get_start(x);
|
||||
for (std::size_t i = 0; i <= range<<1; ++i, cur = next_domain_point(cur))
|
||||
{
|
||||
auto y0 = *f0(cur);
|
||||
auto y1 = *f1(cur);
|
||||
const output_type got = recon(y0, y1);
|
||||
if (cur == x)
|
||||
{
|
||||
ASSERT_EQ(got, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(got, zero_output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr auto to_integral_type = dpf::utils::to_integral_type<input_type>{};
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output = dpf::utils::make_from_integral_value<output_type>{};
|
||||
|
||||
std::vector<T> params;
|
||||
std::size_t range;
|
||||
output_type zero_output;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EvalPointTest);
|
||||
|
||||
TYPED_TEST_P(EvalPointTest, Basic)
|
||||
{
|
||||
using input_type = typename TestFixture::input_type;
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
|
||||
this->assert_wrapper(x, y,
|
||||
[&dpf0](input_type cur)
|
||||
{
|
||||
return dpf::eval_point(dpf0, cur);
|
||||
},
|
||||
[&dpf1](input_type cur)
|
||||
{
|
||||
return dpf::eval_point(dpf1, cur);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalPointTest, BasicPathMemoizer)
|
||||
{
|
||||
using input_type = typename TestFixture::input_type;
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
using key0_t = std::decay_t<decltype(dpf0)>;
|
||||
using key1_t = std::decay_t<decltype(dpf1)>;
|
||||
auto memo0 = dpf::make_basic_path_memoizer<key0_t>(),
|
||||
memo1 = dpf::make_basic_path_memoizer<key1_t>();
|
||||
|
||||
this->assert_wrapper(x, y,
|
||||
[&dpf0, &memo0](input_type cur)
|
||||
{
|
||||
return dpf::eval_point(dpf0, cur, memo0);
|
||||
},
|
||||
[&dpf1, &memo1](input_type cur)
|
||||
{
|
||||
return dpf::eval_point(dpf1, cur, memo1);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalPointTest, NonmemoizingPathMemoizer)
|
||||
{
|
||||
using input_type = typename TestFixture::input_type;
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
using key0_t = std::decay_t<decltype(dpf0)>;
|
||||
using key1_t = std::decay_t<decltype(dpf1)>;
|
||||
auto memo0 = dpf::make_nonmemoizing_path_memoizer<key0_t>(),
|
||||
memo1 = dpf::make_nonmemoizing_path_memoizer<key1_t>();
|
||||
|
||||
this->assert_wrapper(x, y,
|
||||
[&dpf0, &memo0](input_type cur)
|
||||
{
|
||||
return dpf::eval_point(dpf0, cur, memo0);
|
||||
},
|
||||
[&dpf1, &memo1](input_type cur)
|
||||
{
|
||||
return dpf::eval_point(dpf1, cur, memo1);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EvalPointTest,
|
||||
Basic,
|
||||
BasicPathMemoizer,
|
||||
NonmemoizingPathMemoizer);
|
||||
using Types = testing::Types
|
||||
<
|
||||
// base test
|
||||
test_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
test_type<int16_t, uint64_t>,
|
||||
test_type<uint8_t, uint64_t>,
|
||||
test_type<uint64_t, uint64_t>,
|
||||
test_type<simde_int128, uint64_t>,
|
||||
test_type<simde_uint128, uint64_t>,
|
||||
test_type<dpf::bitstring<10>, uint64_t>,
|
||||
test_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
test_type<dpf::modint<10>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
test_type<uint16_t, int64_t>,
|
||||
test_type<uint16_t, uint8_t>,
|
||||
test_type<uint16_t, simde_int128>,
|
||||
test_type<uint16_t, simde_uint128>,
|
||||
test_type<uint16_t, dpf::bit>,
|
||||
test_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
test_type<uint16_t, dpf::bitstring<150>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
test_type<custom_input_type, uint64_t>,
|
||||
test_type<uint16_t, custom_output_type_small>,
|
||||
test_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
test_type<uint16_t, custom_output_type_large_xor>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(EvalPointTestInstantiation, EvalPointTest, Types);
|
||||
715
test/tests/eval_sequence_multi_test.cpp
Normal file
715
test/tests/eval_sequence_multi_test.cpp
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "helpers/eval_common_multi_data.hpp"
|
||||
|
||||
template <typename T>
|
||||
struct EvalSequenceMultiTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
using input_type = typename std::tuple_element_t<0, T>;
|
||||
using output_type0 = typename std::tuple_element_t<1, T>;
|
||||
using output_type1 = typename std::tuple_element_t<2, T>;
|
||||
using output_type2 = typename std::tuple_element_t<3, T>;
|
||||
using output_type3 = typename std::tuple_element_t<4, T>;
|
||||
using integral_type = dpf::utils::integral_type_from_bitlength_t<dpf::utils::bitlength_of_v<input_type>>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type0, output_type1, output_type2, output_type3>;
|
||||
|
||||
protected:
|
||||
EvalSequenceMultiTest()
|
||||
: params{std::get<std::vector<T>>(allParams)},
|
||||
range{std::size_t(1) << std::min(dpf::utils::bitlength_of_v<input_type>, std::size_t(10))-1},
|
||||
zero_output0{from_integral_type_output0(0)},
|
||||
zero_output1{from_integral_type_output1(0)},
|
||||
zero_output2{from_integral_type_output2(0)},
|
||||
zero_output3{from_integral_type_output3(0)},
|
||||
points{get_points()}
|
||||
{ }
|
||||
|
||||
void SetUp() override
|
||||
{ }
|
||||
|
||||
void TearDown() override
|
||||
{ }
|
||||
|
||||
std::set<input_type> get_points()
|
||||
{
|
||||
std::set<input_type> ret;
|
||||
// insert all `x`'s used in tests
|
||||
for (auto [x, y0, y1, y2, y3] : params)
|
||||
{
|
||||
ret.insert(x);
|
||||
}
|
||||
// insert additional points until sufficient random points
|
||||
while (ret.size() < range)
|
||||
{
|
||||
ret.emplace(from_integral_type(dpf::uniform_sample<integral_type>()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename IterableT0, typename IterableT1>
|
||||
void assert_wrapper(const input_type & x, const output_type0 & y0,
|
||||
const output_type1 & y1, const output_type2 & y2, const output_type3 & y3,
|
||||
IterableT0 & iter0, IterableT1 & iter1)
|
||||
{
|
||||
auto zip0 = dpf::tuple_as_zip(iter0);
|
||||
auto zip1 = dpf::tuple_as_zip(iter1);
|
||||
auto it0 = std::cbegin(zip0);
|
||||
auto it1 = std::cbegin(zip1);
|
||||
auto cur = points.cbegin();
|
||||
for (std::size_t i = 0; i < range; ++i, ++cur, ++it0, ++it1)
|
||||
{
|
||||
if (*cur == x)
|
||||
{
|
||||
ASSERT_EQ(recon(std::get<0>(*it0), std::get<0>(*it1)), y0);
|
||||
ASSERT_EQ(recon(std::get<1>(*it0), std::get<1>(*it1)), y1);
|
||||
ASSERT_EQ(recon(std::get<2>(*it0), std::get<2>(*it1)), y2);
|
||||
ASSERT_EQ(recon(std::get<3>(*it0), std::get<3>(*it1)), y3);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(recon(std::get<0>(*it0), std::get<0>(*it1)), zero_output0);
|
||||
ASSERT_EQ(recon(std::get<1>(*it0), std::get<1>(*it1)), zero_output1);
|
||||
ASSERT_EQ(recon(std::get<2>(*it0), std::get<2>(*it1)), zero_output2);
|
||||
ASSERT_EQ(recon(std::get<3>(*it0), std::get<3>(*it1)), zero_output3);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(zip0));
|
||||
ASSERT_EQ(it1, std::end(zip1));
|
||||
}
|
||||
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output0 = dpf::utils::make_from_integral_value<output_type0>{};
|
||||
static constexpr auto from_integral_type_output1 = dpf::utils::make_from_integral_value<output_type1>{};
|
||||
static constexpr auto from_integral_type_output2 = dpf::utils::make_from_integral_value<output_type2>{};
|
||||
static constexpr auto from_integral_type_output3 = dpf::utils::make_from_integral_value<output_type3>{};
|
||||
|
||||
std::vector<T> params;
|
||||
std::size_t range;
|
||||
output_type0 zero_output0;
|
||||
output_type1 zero_output1;
|
||||
output_type2 zero_output2;
|
||||
output_type3 zero_output3;
|
||||
std::set<input_type> points;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EvalSequenceMultiTest);
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, NoRecipeBasic)
|
||||
{
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, this->points.begin(), this->points.end());
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, this->points.begin(), this->points.end());
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, NoRecipeBasicEntireNode)
|
||||
{
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, this->points.begin(), this->points.end(), dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, this->points.begin(), this->points.end(), dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, NoRecipeBasicOutputOnly)
|
||||
{
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, this->points.begin(), this->points.end(), dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, this->points.begin(), this->points.end(), dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, NoRecipeOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_subsequence<dpf_type, 0, 1, 2, 3>(this->points.begin(), this->points.end()),
|
||||
buf1 = dpf::make_output_buffer_for_subsequence<dpf_type, 0, 1, 2, 3>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, this->points.begin(), this->points.end(), buf0),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, this->points.begin(), this->points.end(), buf1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, NoRecipeOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_subsequence<dpf_type, 0, 1, 2, 3>(this->points.begin(), this->points.end()),
|
||||
buf1 = dpf::make_output_buffer_for_subsequence<dpf_type, 0, 1, 2, 3>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, this->points.begin(), this->points.end(), buf0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, this->points.begin(), this->points.end(), buf1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, NoRecipeOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_subsequence<dpf_type, 0, 1, 2, 3>(this->points.begin(), this->points.end()),
|
||||
buf1 = dpf::make_output_buffer_for_subsequence<dpf_type, 0, 1, 2, 3>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, this->points.begin(), this->points.end(), buf0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, this->points.begin(), this->points.end(), buf1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeBasic)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0);
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeBasicEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeBasicOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeInplaceReversingSequenceMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeInplaceReversingSequenceMemoizerEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0, dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeInplaceReversingSequenceMemoizerOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0, dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeDoubleSpaceSequenceMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeDoubleSpaceSequenceMemoizerEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0, dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeDoubleSpaceSequenceMemoizerOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0, dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeFullTreeSequenceMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeFullTreeSequenceMemoizerEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0, dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeFullTreeSequenceMemoizerOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto [buf0, iter0] = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, memo0, dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeInplaceReversingSequenceMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeInplaceReversingSequenceMemoizerOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeInplaceReversingSequenceMemoizerOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeDoubleSpaceSequenceMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeDoubleSpaceSequenceMemoizerOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeDoubleSpaceSequenceMemoizerOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeFullTreeSequenceMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeFullTreeSequenceMemoizerOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceMultiTest, RecipeFullTreeSequenceMemoizerOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type, 0, 1, 2, 3>(recipe1);
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y0, y1, y2, y3] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1, y2, y3);
|
||||
auto iter0 = dpf::eval_sequence<0, 1, 2, 3>(dpf0, recipe0, buf0, memo0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence<0, 1, 2, 3>(dpf1, recipe1, buf1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y0, y1, y2, y3, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EvalSequenceMultiTest,
|
||||
NoRecipeBasic,
|
||||
NoRecipeBasicEntireNode,
|
||||
NoRecipeBasicOutputOnly,
|
||||
NoRecipeOutbuf,
|
||||
NoRecipeOutbufEntireNode,
|
||||
NoRecipeOutbufOutputOnly,
|
||||
RecipeBasic,
|
||||
RecipeBasicEntireNode,
|
||||
RecipeBasicOutputOnly,
|
||||
RecipeOutbuf,
|
||||
RecipeOutbufEntireNode,
|
||||
RecipeOutbufOutputOnly,
|
||||
RecipeInplaceReversingSequenceMemoizer,
|
||||
RecipeInplaceReversingSequenceMemoizerEntireNode,
|
||||
RecipeInplaceReversingSequenceMemoizerOutputOnly,
|
||||
RecipeDoubleSpaceSequenceMemoizer,
|
||||
RecipeDoubleSpaceSequenceMemoizerEntireNode,
|
||||
RecipeDoubleSpaceSequenceMemoizerOutputOnly,
|
||||
RecipeFullTreeSequenceMemoizer,
|
||||
RecipeFullTreeSequenceMemoizerEntireNode,
|
||||
RecipeFullTreeSequenceMemoizerOutputOnly,
|
||||
RecipeInplaceReversingSequenceMemoizerOutbuf,
|
||||
RecipeInplaceReversingSequenceMemoizerOutbufEntireNode,
|
||||
RecipeInplaceReversingSequenceMemoizerOutbufOutputOnly,
|
||||
RecipeDoubleSpaceSequenceMemoizerOutbuf,
|
||||
RecipeDoubleSpaceSequenceMemoizerOutbufEntireNode,
|
||||
RecipeDoubleSpaceSequenceMemoizerOutbufOutputOnly,
|
||||
RecipeFullTreeSequenceMemoizerOutbuf,
|
||||
RecipeFullTreeSequenceMemoizerOutbufEntireNode,
|
||||
RecipeFullTreeSequenceMemoizerOutbufOutputOnly);
|
||||
using Types = testing::Types
|
||||
<
|
||||
// base test
|
||||
test_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
test_type<int16_t, uint64_t>,
|
||||
test_type<uint8_t, uint64_t>,
|
||||
test_type<uint64_t, uint64_t>,
|
||||
test_type<simde_int128, uint64_t>,
|
||||
test_type<simde_uint128, uint64_t>,
|
||||
test_type<dpf::bitstring<10>, uint64_t>,
|
||||
test_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
test_type<dpf::modint<10>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
test_type<uint16_t, int64_t>,
|
||||
test_type<uint16_t, uint8_t>,
|
||||
test_type<uint16_t, simde_int128>,
|
||||
test_type<uint16_t, simde_uint128>,
|
||||
test_type<uint16_t, dpf::bit>,
|
||||
test_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
test_type<uint16_t, dpf::bitstring<150>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
test_type<custom_input_type, uint64_t>,
|
||||
test_type<uint16_t, custom_output_type_small>,
|
||||
test_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
test_type<uint16_t, custom_output_type_large_xor>,
|
||||
|
||||
// distinct output types
|
||||
multi_test_type<uint16_t, uint32_t, dpf::xor_wrapper<uint32_t>, dpf::bitstring<20, uint8_t>, dpf::bitstring<32>>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(EvalSequenceMultiTestInstantiation, EvalSequenceMultiTest, Types);
|
||||
721
test/tests/eval_sequence_test.cpp
Normal file
721
test/tests/eval_sequence_test.cpp
Normal file
|
|
@ -0,0 +1,721 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include "helpers/eval_common_data.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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
|
||||
return a - b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
struct EvalSequenceTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
using input_type = typename std::tuple_element_t<0, T>;
|
||||
using output_type = typename std::tuple_element_t<1, T>;
|
||||
using integral_type = dpf::utils::integral_type_from_bitlength_t<dpf::utils::bitlength_of_v<input_type>>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
|
||||
protected:
|
||||
EvalSequenceTest()
|
||||
: params{std::get<std::vector<T>>(allParams)},
|
||||
range{std::size_t(1) << std::min(dpf::utils::bitlength_of_v<input_type>, std::size_t(10))-1},
|
||||
zero_output{from_integral_type_output(0)},
|
||||
points{get_points()}
|
||||
{ }
|
||||
|
||||
void SetUp() override
|
||||
{ }
|
||||
|
||||
void TearDown() override
|
||||
{ }
|
||||
|
||||
std::set<input_type> get_points()
|
||||
{
|
||||
std::set<input_type> ret;
|
||||
// insert all `x`'s used in tests
|
||||
for (auto [x, y] : params)
|
||||
{
|
||||
ret.insert(x);
|
||||
}
|
||||
// insert additional points until sufficient random points
|
||||
while (ret.size() < range)
|
||||
{
|
||||
ret.emplace(from_integral_type(dpf::uniform_sample<integral_type>()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename IterableT0, typename IterableT1>
|
||||
void assert_wrapper(const input_type & x, const output_type & y,
|
||||
const IterableT0 & iter0, const IterableT1 & iter1)
|
||||
{
|
||||
auto it0 = std::begin(iter0);
|
||||
auto it1 = std::begin(iter1);
|
||||
auto cur = points.cbegin();
|
||||
for (std::size_t i = 0; i < range; ++i, ++cur, ++it0, ++it1)
|
||||
{
|
||||
if (*cur == x)
|
||||
{
|
||||
ASSERT_EQ(recon(*it0, *it1), y);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(recon(*it0, *it1), zero_output);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(iter0));
|
||||
ASSERT_EQ(it1, std::end(iter1));
|
||||
}
|
||||
|
||||
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
|
||||
static constexpr auto from_integral_type_output = dpf::utils::make_from_integral_value<output_type>{};
|
||||
|
||||
std::vector<T> params;
|
||||
std::size_t range;
|
||||
output_type zero_output;
|
||||
std::set<input_type> points;
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE_P(EvalSequenceTest);
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, NoRecipeBasic)
|
||||
{
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, this->points.begin(), this->points.end());
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, this->points.begin(), this->points.end());
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, NoRecipeBasicEntireNode)
|
||||
{
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, this->points.begin(), this->points.end(), dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, this->points.begin(), this->points.end(), dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, NoRecipeBasicOutputOnly)
|
||||
{
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, this->points.begin(), this->points.end(), dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, this->points.begin(), this->points.end(), dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, NoRecipeOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_subsequence<dpf_type>(this->points.begin(), this->points.end()),
|
||||
buf1 = dpf::make_output_buffer_for_subsequence<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, this->points.begin(), this->points.end(), buf0),
|
||||
iter1 = dpf::eval_sequence(dpf1, this->points.begin(), this->points.end(), buf1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, NoRecipeOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_subsequence<dpf_type>(this->points.begin(), this->points.end()),
|
||||
buf1 = dpf::make_output_buffer_for_subsequence<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, this->points.begin(), this->points.end(), buf0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, this->points.begin(), this->points.end(), buf1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, NoRecipeOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_subsequence<dpf_type>(this->points.begin(), this->points.end()),
|
||||
buf1 = dpf::make_output_buffer_for_subsequence<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, this->points.begin(), this->points.end(), buf0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, this->points.begin(), this->points.end(), buf1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, BreadthFirstBasic)
|
||||
{
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence_breadth_first(dpf0, this->points.begin(), this->points.end());
|
||||
auto [buf1, iter1] = dpf::eval_sequence_breadth_first(dpf1, this->points.begin(), this->points.end());
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, BreadthFirstOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto buf0 = dpf::make_output_buffer_for_subsequence<dpf_type>(this->points.begin(), this->points.end()),
|
||||
buf1 = dpf::make_output_buffer_for_subsequence<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence_breadth_first(dpf0, this->points.begin(), this->points.end(), buf0),
|
||||
iter1 = dpf::eval_sequence_breadth_first(dpf1, this->points.begin(), this->points.end(), buf1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeBasic)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0);
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeBasicEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeBasicOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeInplaceReversingSequenceMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeInplaceReversingSequenceMemoizerEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0, dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeInplaceReversingSequenceMemoizerOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0, dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeDoubleSpaceSequenceMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeDoubleSpaceSequenceMemoizerEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0, dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeDoubleSpaceSequenceMemoizerOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0, dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeFullTreeSequenceMemoizer)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0);
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeFullTreeSequenceMemoizerEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0, dpf::return_entire_node_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeFullTreeSequenceMemoizerOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_sequence(dpf0, recipe0, memo0, dpf::return_output_only_tag_{});
|
||||
auto [buf1, iter1] = dpf::eval_sequence(dpf1, recipe1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeInplaceReversingSequenceMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeInplaceReversingSequenceMemoizerOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeInplaceReversingSequenceMemoizerOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_inplace_reversing_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeDoubleSpaceSequenceMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeDoubleSpaceSequenceMemoizerOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeDoubleSpaceSequenceMemoizerOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_double_space_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeFullTreeSequenceMemoizerOutbuf)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1);
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeFullTreeSequenceMemoizerOutbufEntireNode)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0, dpf::return_entire_node_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1, dpf::return_entire_node_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(EvalSequenceTest, RecipeFullTreeSequenceMemoizerOutbufOutputOnly)
|
||||
{
|
||||
using dpf_type = typename TestFixture::dpf_type;
|
||||
auto recipe0 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end()),
|
||||
recipe1 = dpf::make_sequence_recipe<dpf_type>(this->points.begin(), this->points.end());
|
||||
auto buf0 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe0),
|
||||
buf1 = dpf::make_output_buffer_for_recipe_subsequence<dpf_type>(recipe1);
|
||||
auto memo0 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe0),
|
||||
memo1 = dpf::make_full_tree_sequence_memoizer<dpf_type>(recipe1);
|
||||
|
||||
for (auto [x, y] : this->params)
|
||||
{
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto iter0 = dpf::eval_sequence(dpf0, recipe0, buf0, memo0, dpf::return_output_only_tag_{}),
|
||||
iter1 = dpf::eval_sequence(dpf1, recipe1, buf1, memo1, dpf::return_output_only_tag_{});
|
||||
|
||||
this->assert_wrapper(x, y, iter0, iter1);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(EvalSequenceTest,
|
||||
NoRecipeBasic,
|
||||
NoRecipeBasicEntireNode,
|
||||
NoRecipeBasicOutputOnly,
|
||||
NoRecipeOutbuf,
|
||||
NoRecipeOutbufEntireNode,
|
||||
NoRecipeOutbufOutputOnly,
|
||||
BreadthFirstBasic,
|
||||
BreadthFirstOutbuf,
|
||||
RecipeBasic,
|
||||
RecipeBasicEntireNode,
|
||||
RecipeBasicOutputOnly,
|
||||
RecipeOutbuf,
|
||||
RecipeOutbufEntireNode,
|
||||
RecipeOutbufOutputOnly,
|
||||
RecipeInplaceReversingSequenceMemoizer,
|
||||
RecipeInplaceReversingSequenceMemoizerEntireNode,
|
||||
RecipeInplaceReversingSequenceMemoizerOutputOnly,
|
||||
RecipeDoubleSpaceSequenceMemoizer,
|
||||
RecipeDoubleSpaceSequenceMemoizerEntireNode,
|
||||
RecipeDoubleSpaceSequenceMemoizerOutputOnly,
|
||||
RecipeFullTreeSequenceMemoizer,
|
||||
RecipeFullTreeSequenceMemoizerEntireNode,
|
||||
RecipeFullTreeSequenceMemoizerOutputOnly,
|
||||
RecipeInplaceReversingSequenceMemoizerOutbuf,
|
||||
RecipeInplaceReversingSequenceMemoizerOutbufEntireNode,
|
||||
RecipeInplaceReversingSequenceMemoizerOutbufOutputOnly,
|
||||
RecipeDoubleSpaceSequenceMemoizerOutbuf,
|
||||
RecipeDoubleSpaceSequenceMemoizerOutbufEntireNode,
|
||||
RecipeDoubleSpaceSequenceMemoizerOutbufOutputOnly,
|
||||
RecipeFullTreeSequenceMemoizerOutbuf,
|
||||
RecipeFullTreeSequenceMemoizerOutbufEntireNode,
|
||||
RecipeFullTreeSequenceMemoizerOutbufOutputOnly);
|
||||
using Types = testing::Types
|
||||
<
|
||||
// base test
|
||||
test_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
test_type<int16_t, uint64_t>,
|
||||
test_type<uint8_t, uint64_t>,
|
||||
test_type<uint64_t, uint64_t>,
|
||||
test_type<simde_int128, uint64_t>,
|
||||
test_type<simde_uint128, uint64_t>,
|
||||
test_type<dpf::bitstring<10>, uint64_t>,
|
||||
test_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
test_type<dpf::modint<10>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
test_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
test_type<uint16_t, int64_t>,
|
||||
test_type<uint16_t, uint8_t>,
|
||||
test_type<uint16_t, simde_int128>,
|
||||
test_type<uint16_t, simde_uint128>,
|
||||
test_type<uint16_t, dpf::bit>,
|
||||
test_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
test_type<uint16_t, dpf::bitstring<150>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
test_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
test_type<custom_input_type, uint64_t>,
|
||||
test_type<uint16_t, custom_output_type_small>,
|
||||
test_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
test_type<uint16_t, custom_output_type_large_xor>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(EvalSequenceTestInstantiation, EvalSequenceTest, Types);
|
||||
1123
test/tests/geneval_test.cpp
Normal file
1123
test/tests/geneval_test.cpp
Normal file
File diff suppressed because it is too large
Load diff
160
test/tests/helpers/custom_input_type.hpp
Normal file
160
test/tests/helpers/custom_input_type.hpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#include <cstdint>
|
||||
|
||||
class custom_input_type
|
||||
{
|
||||
public:
|
||||
constexpr custom_input_type()
|
||||
: val_{0}
|
||||
{ }
|
||||
|
||||
constexpr custom_input_type(uint16_t val)
|
||||
: val_{val}
|
||||
{ }
|
||||
|
||||
custom_input_type operator<<(std::size_t shift) const
|
||||
{
|
||||
return custom_input_type{static_cast<uint16_t>(val_ << shift)};
|
||||
}
|
||||
|
||||
custom_input_type & operator<<=(std::size_t shift)
|
||||
{
|
||||
this->val_ <<= shift;
|
||||
return *this;
|
||||
}
|
||||
|
||||
custom_input_type operator>>(std::size_t shift) const
|
||||
{
|
||||
return custom_input_type{static_cast<uint16_t>(val_ >> shift)};
|
||||
}
|
||||
|
||||
custom_input_type & operator>>=(std::size_t shift)
|
||||
{
|
||||
this->val_ >>= shift;
|
||||
return *this;
|
||||
}
|
||||
|
||||
custom_input_type operator&(const custom_input_type & rhs) const
|
||||
{
|
||||
return custom_input_type{static_cast<uint16_t>(this->val_ & rhs.val_)};
|
||||
}
|
||||
|
||||
custom_input_type operator^(const custom_input_type & rhs) const
|
||||
{
|
||||
return custom_input_type{static_cast<uint16_t>(this->val_ ^ rhs.val_)};
|
||||
}
|
||||
|
||||
custom_input_type operator~() const
|
||||
{
|
||||
return custom_input_type{static_cast<uint16_t>(~this->val_)};
|
||||
}
|
||||
|
||||
custom_input_type & operator++()
|
||||
{
|
||||
++this->val_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
custom_input_type operator++(int)
|
||||
{
|
||||
custom_input_type tmp = *this;
|
||||
this->operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
custom_input_type & operator--()
|
||||
{
|
||||
--this->val_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
custom_input_type operator--(int)
|
||||
{
|
||||
custom_input_type tmp = *this;
|
||||
this->operator--();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const custom_input_type & rhs) const
|
||||
{
|
||||
return this->val_ == rhs.val_;
|
||||
}
|
||||
|
||||
bool operator>(const custom_input_type & rhs) const
|
||||
{
|
||||
return this->val_ > rhs.val_;
|
||||
}
|
||||
|
||||
bool operator>=(const custom_input_type & rhs) const
|
||||
{
|
||||
return this->val_ >= rhs.val_;
|
||||
}
|
||||
|
||||
bool operator<(const custom_input_type & rhs) const
|
||||
{
|
||||
return this->val_ < rhs.val_;
|
||||
}
|
||||
|
||||
bool operator<=(const custom_input_type & rhs) const
|
||||
{
|
||||
return this->val_ <= rhs.val_;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return static_cast<bool>(this->val_);
|
||||
}
|
||||
|
||||
operator uint16_t() const
|
||||
{
|
||||
return val_;
|
||||
}
|
||||
|
||||
operator uint64_t() const
|
||||
{
|
||||
return static_cast<uint64_t>(val_);
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t val_;
|
||||
};
|
||||
|
||||
namespace dpf::utils
|
||||
{
|
||||
|
||||
template <>
|
||||
struct msb_of<custom_input_type>
|
||||
{
|
||||
static constexpr custom_input_type value{0x8000};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct mod_pow_2<custom_input_type>
|
||||
{
|
||||
std::size_t operator()(custom_input_type val, std::size_t n) const noexcept
|
||||
{
|
||||
return static_cast<std::size_t>(static_cast<uint16_t>(val) % (1ul << n));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<>
|
||||
class numeric_limits<custom_input_type>
|
||||
: public numeric_limits<uint16_t> {};
|
||||
|
||||
template<>
|
||||
class numeric_limits<custom_input_type const>
|
||||
: public numeric_limits<custom_input_type> {};
|
||||
|
||||
template<>
|
||||
class numeric_limits<custom_input_type volatile>
|
||||
: public numeric_limits<custom_input_type> {};
|
||||
|
||||
template<>
|
||||
class numeric_limits<custom_input_type const volatile>
|
||||
: public numeric_limits<custom_input_type> {};
|
||||
|
||||
}
|
||||
54
test/tests/helpers/custom_output_type_large_plus_minus.hpp
Normal file
54
test/tests/helpers/custom_output_type_large_plus_minus.hpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#include <cstdint>
|
||||
|
||||
class custom_output_type_large_plus_minus
|
||||
{
|
||||
public:
|
||||
constexpr custom_output_type_large_plus_minus()
|
||||
: a_{0}, b_{0}, c_{0}, d_{0}
|
||||
{ }
|
||||
|
||||
constexpr custom_output_type_large_plus_minus(uint64_t val)
|
||||
: a_{val}, b_{val}, c_{val}, d_{val}
|
||||
{ }
|
||||
|
||||
constexpr custom_output_type_large_plus_minus(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
|
||||
: a_{a}, b_{b}, c_{c}, d_{d}
|
||||
{ }
|
||||
|
||||
custom_output_type_large_plus_minus operator+(const custom_output_type_large_plus_minus & rhs) const
|
||||
{
|
||||
return custom_output_type_large_plus_minus{this->a_ + rhs.a_, this->b_ + rhs.b_, this->c_ + rhs.c_, this->d_ + rhs.d_};
|
||||
}
|
||||
|
||||
custom_output_type_large_plus_minus operator-(const custom_output_type_large_plus_minus & rhs) const
|
||||
{
|
||||
return custom_output_type_large_plus_minus{this->a_ - rhs.a_, this->b_ - rhs.b_, this->c_ - rhs.c_, this->d_ - rhs.d_};
|
||||
}
|
||||
|
||||
custom_output_type_large_plus_minus operator^(const custom_output_type_large_plus_minus & rhs) const
|
||||
{
|
||||
return custom_output_type_large_plus_minus{this->a_ ^ rhs.a_, this->b_ ^ rhs.b_, this->c_ ^ rhs.c_, this->d_ ^ rhs.d_};
|
||||
}
|
||||
|
||||
bool operator==(const custom_output_type_large_plus_minus & rhs) const
|
||||
{
|
||||
return this->a_ == rhs.a_ && this->b_ == rhs.b_ && this->c_ == rhs.c_ && this->d_ == rhs.d_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t a_, b_, c_, d_;
|
||||
};
|
||||
|
||||
namespace dpf::utils
|
||||
{
|
||||
|
||||
template <>
|
||||
struct make_from_integral_value<custom_output_type_large_plus_minus>
|
||||
{
|
||||
constexpr custom_output_type_large_plus_minus operator()(uint64_t val) const noexcept
|
||||
{
|
||||
return custom_output_type_large_plus_minus{val, val, val, val};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
49
test/tests/helpers/custom_output_type_large_xor.hpp
Normal file
49
test/tests/helpers/custom_output_type_large_xor.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#include <cstdint>
|
||||
|
||||
class custom_output_type_large_xor
|
||||
{
|
||||
public:
|
||||
constexpr custom_output_type_large_xor()
|
||||
: a_{0}, b_{0}, c_{0}, d_{0}
|
||||
{ }
|
||||
|
||||
constexpr custom_output_type_large_xor(uint64_t val)
|
||||
: a_{val}, b_{val}, c_{val}, d_{val}
|
||||
{ }
|
||||
|
||||
constexpr custom_output_type_large_xor(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
|
||||
: a_{a}, b_{b}, c_{c}, d_{d}
|
||||
{ }
|
||||
|
||||
custom_output_type_large_xor operator-(const custom_output_type_large_xor & rhs) const
|
||||
{
|
||||
return this->operator^(rhs);
|
||||
}
|
||||
|
||||
custom_output_type_large_xor operator^(const custom_output_type_large_xor & rhs) const
|
||||
{
|
||||
return custom_output_type_large_xor{this->a_ ^ rhs.a_, this->b_ ^ rhs.b_, this->c_ ^ rhs.c_, this->d_ ^ rhs.d_};
|
||||
}
|
||||
|
||||
bool operator==(const custom_output_type_large_xor & rhs) const
|
||||
{
|
||||
return this->a_ == rhs.a_ && this->b_ == rhs.b_ && this->c_ == rhs.c_ && this->d_ == rhs.d_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t a_, b_, c_, d_;
|
||||
};
|
||||
|
||||
namespace dpf::utils
|
||||
{
|
||||
|
||||
template <>
|
||||
struct make_from_integral_value<custom_output_type_large_xor>
|
||||
{
|
||||
constexpr custom_output_type_large_xor operator()(uint64_t val) const noexcept
|
||||
{
|
||||
return custom_output_type_large_xor{val, val, val, val};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
48
test/tests/helpers/custom_output_type_small.hpp
Normal file
48
test/tests/helpers/custom_output_type_small.hpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include <cstdint>
|
||||
|
||||
class custom_output_type_small
|
||||
{
|
||||
public:
|
||||
constexpr custom_output_type_small()
|
||||
: val_{0}
|
||||
{ }
|
||||
|
||||
constexpr custom_output_type_small(uint64_t val)
|
||||
: val_{val}
|
||||
{ }
|
||||
|
||||
custom_output_type_small operator+(const custom_output_type_small & rhs) const
|
||||
{
|
||||
return custom_output_type_small{this->val_ + rhs.val_};
|
||||
}
|
||||
|
||||
custom_output_type_small operator-(const custom_output_type_small & rhs) const
|
||||
{
|
||||
return custom_output_type_small{this->val_ - rhs.val_};
|
||||
}
|
||||
|
||||
custom_output_type_small operator^(const custom_output_type_small & rhs) const
|
||||
{
|
||||
return custom_output_type_small{this->val_ ^ rhs.val_};
|
||||
}
|
||||
|
||||
bool operator==(const custom_output_type_small & rhs) const
|
||||
{
|
||||
return this->val_ == rhs.val_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t val_;
|
||||
};
|
||||
|
||||
namespace dpf::leaf_arithmetic
|
||||
{
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
template <> struct add_t<custom_output_type_small, simde__m128i> final : public detail::add2x64_t {};
|
||||
template <> struct subtract_t<custom_output_type_small, simde__m128i> final : public detail::sub2x64_t {};
|
||||
template <> struct multiply_t<custom_output_type_small, simde__m128i> final : public detail::mul2x64_t {};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
|
||||
}
|
||||
24
test/tests/helpers/domain_walk.hpp
Normal file
24
test/tests/helpers/domain_walk.hpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef LIBDPF_TEST_TESTS_HELPERS_DOMAIN_WALK_HPP__
|
||||
#define LIBDPF_TEST_TESTS_HELPERS_DOMAIN_WALK_HPP__
|
||||
|
||||
// eval_interval / eval_full emit points in integer order of the input bits
|
||||
// (the same order as operator++ for ordinary integers). xor_wrapper::operator++
|
||||
// is characteristic-2 addition, XOR 1, so it does not walk that domain.
|
||||
template <typename InputT>
|
||||
InputT next_domain_point(InputT cur)
|
||||
{
|
||||
if constexpr (dpf::utils::has_characteristic_two_v<InputT>)
|
||||
{
|
||||
using narrow = dpf::utils::integral_type_from_bitlength_t<dpf::utils::bitlength_of_v<InputT>>;
|
||||
auto bits = static_cast<narrow>(dpf::utils::to_integral_type<InputT>{}(cur));
|
||||
bits = static_cast<narrow>(bits + narrow{1});
|
||||
return dpf::utils::make_from_integral_value<InputT>{}(bits);
|
||||
}
|
||||
else
|
||||
{
|
||||
++cur;
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LIBDPF_TEST_TESTS_HELPERS_DOMAIN_WALK_HPP__
|
||||
664
test/tests/helpers/eval_common_data.hpp
Normal file
664
test/tests/helpers/eval_common_data.hpp
Normal file
|
|
@ -0,0 +1,664 @@
|
|||
#ifndef LIBDPF_TEST_TESTS_HELPERS_EVAL_COMMON_DATA_HPP__
|
||||
#define LIBDPF_TEST_TESTS_HELPERS_EVAL_COMMON_DATA_HPP__
|
||||
|
||||
#include "custom_input_type.hpp"
|
||||
#include "custom_output_type_small.hpp"
|
||||
#include "custom_output_type_large_plus_minus.hpp"
|
||||
#include "custom_output_type_large_xor.hpp"
|
||||
#include "domain_walk.hpp"
|
||||
|
||||
template <typename InputT,
|
||||
typename OutputT>
|
||||
using test_type = std::tuple<InputT, OutputT>;
|
||||
|
||||
template <typename InputT,
|
||||
typename OutputT>
|
||||
using param_type = std::vector<test_type<InputT, OutputT>>;
|
||||
|
||||
using dpf::literals::operator""_bitstring;
|
||||
using dpf::literals::operator""_bitstring_8;
|
||||
|
||||
static std::tuple
|
||||
<
|
||||
// base test
|
||||
param_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
param_type<int16_t, uint64_t>,
|
||||
param_type<uint8_t, uint64_t>,
|
||||
param_type<uint64_t, uint64_t>,
|
||||
param_type<simde_int128, uint64_t>,
|
||||
param_type<simde_uint128, uint64_t>,
|
||||
param_type<dpf::bitstring<10>, uint64_t>,
|
||||
param_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
param_type<dpf::modint<10>, uint64_t>,
|
||||
param_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
param_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
param_type<uint16_t, int64_t>,
|
||||
param_type<uint16_t, uint8_t>,
|
||||
param_type<uint16_t, simde_int128>,
|
||||
param_type<uint16_t, simde_uint128>,
|
||||
param_type<uint16_t, dpf::bit>,
|
||||
param_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
param_type<uint16_t, dpf::bitstring<150>>,
|
||||
param_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
param_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
param_type<custom_input_type, uint64_t>,
|
||||
param_type<uint16_t, custom_output_type_small>,
|
||||
param_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
param_type<uint16_t, custom_output_type_large_xor>
|
||||
> allParams
|
||||
{
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x0000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x0000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x0000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x5555), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x5555), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x5555), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x5555), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x8000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x8000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x8000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x8000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(int16_t(0x0000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(int16_t(0x0000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(int16_t(0x0000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(int16_t(0x0000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0x5555), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(int16_t(0x5555), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(int16_t(0x5555), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(int16_t(0x5555), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0x7FFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(int16_t(0x7FFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(int16_t(0x7FFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(int16_t(0x7FFF), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0x8000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(int16_t(0x8000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(int16_t(0x8000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(int16_t(0x8000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0xAAAA), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(int16_t(0xAAAA), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(int16_t(0xAAAA), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(int16_t(0xAAAA), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0xFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(int16_t(0xFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(int16_t(0xFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(int16_t(0xFFFF), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint8_t(0x00), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint8_t(0x00), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint8_t(0x00), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint8_t(0x00), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0x55), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint8_t(0x55), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint8_t(0x55), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint8_t(0x55), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0x7F), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint8_t(0x7F), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint8_t(0x7F), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint8_t(0x7F), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0x80), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint8_t(0x80), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint8_t(0x80), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint8_t(0x80), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0xAA), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint8_t(0xAA), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint8_t(0xAA), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint8_t(0xAA), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0xFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint8_t(0xFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint8_t(0xFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint8_t(0xFF), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint64_t(0x0000000000000000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint64_t(0x0000000000000000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint64_t(0x0000000000000000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint64_t(0x0000000000000000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0x5555555555555555), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint64_t(0x5555555555555555), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint64_t(0x5555555555555555), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint64_t(0x5555555555555555), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0x7FFFFFFFFFFFFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint64_t(0x7FFFFFFFFFFFFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint64_t(0x7FFFFFFFFFFFFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint64_t(0x7FFFFFFFFFFFFFFF), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0X8000000000000000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint64_t(0X8000000000000000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint64_t(0X8000000000000000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint64_t(0X8000000000000000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0xAAAAAAAAAAAAAAAA), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint64_t(0xAAAAAAAAAAAAAAAA), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint64_t(0xAAAAAAAAAAAAAAAA), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint64_t(0xAAAAAAAAAAAAAAAA), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint64_t(0xFFFFFFFFFFFFFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint64_t(0xFFFFFFFFFFFFFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint64_t(0xFFFFFFFFFFFFFFFF), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0x7FFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_int128(0x7FFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_int128(0x7FFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_int128(0x7FFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0x8000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_int128(0x8000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_int128(0x8000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_int128(0x8000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0x7FFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_uint128(0x7FFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_uint128(0x7FFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_uint128(0x7FFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0x8000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_uint128(0x8000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_uint128(0x8000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_uint128(0x8000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(0000000000_bitstring, uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(0000000000_bitstring, uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(0000000000_bitstring, uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(0000000000_bitstring, uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(0101010101_bitstring, uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(0101010101_bitstring, uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(0101010101_bitstring, uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(0101010101_bitstring, uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(0111111111_bitstring, uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(0111111111_bitstring, uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(0111111111_bitstring, uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(0111111111_bitstring, uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(1000000000_bitstring, uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(1000000000_bitstring, uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(1000000000_bitstring, uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(1000000000_bitstring, uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(1010101010_bitstring, uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(1010101010_bitstring, uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(1010101010_bitstring, uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(1010101010_bitstring, uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(1111111111_bitstring, uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(1111111111_bitstring, uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(1111111111_bitstring, uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(1111111111_bitstring, uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("000"), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("000"), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("000"), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("000"), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("555"), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("555"), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("555"), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("555"), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("7ff"), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("7ff"), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("7ff"), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("7ff"), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("800"), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("800"), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("800"), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("800"), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("aaa"), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("aaa"), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("aaa"), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("aaa"), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("fff"), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("fff"), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("fff"), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("fff"), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
},
|
||||
{
|
||||
std::make_tuple(dpf::modint<10>(0x000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::modint<10>(0x000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::modint<10>(0x000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::modint<10>(0x000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x155), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::modint<10>(0x155), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::modint<10>(0x155), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::modint<10>(0x155), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x1FF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::modint<10>(0x1FF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::modint<10>(0x1FF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::modint<10>(0x1FF), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x200), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::modint<10>(0x200), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::modint<10>(0x200), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::modint<10>(0x200), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x2AA), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::modint<10>(0x2AA), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::modint<10>(0x2AA), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::modint<10>(0x2AA), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x3FF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::modint<10>(0x3FF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::modint<10>(0x3FF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::modint<10>(0x3FF), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
},
|
||||
{
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x0000)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x0000)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x0000)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x0000)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x5555)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x5555)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x5555)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x5555)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x7FFF)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x7FFF)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x7FFF)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x7FFF)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x8000)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x8000)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x8000)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x8000)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xAAAA)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xAAAA)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xAAAA)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xAAAA)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xFFFF)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xFFFF)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xFFFF)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xFFFF)), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x0000)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x0000)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x0000)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x0000)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x5555)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x5555)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x5555)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x5555)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x7FFF)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x7FFF)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x7FFF)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x7FFF)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x8000)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x8000)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x8000)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x8000)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xAAAA)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xAAAA)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xAAAA)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xAAAA)), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xFFFF)), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xFFFF)), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xFFFF)), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xFFFF)), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), int64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x0000), int64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x0000), int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x0000), int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x5555), int64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x5555), int64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x5555), int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x5555), int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), int64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x7FFF), int64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x7FFF), int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x7FFF), int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x8000), int64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x8000), int64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x8000), int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x8000), int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), int64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0xAAAA), int64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0xAAAA), int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0xAAAA), int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), int64_t(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0xFFFF), int64_t(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0xFFFF), int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0xFFFF), int64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), uint8_t(0x01)),
|
||||
std::make_tuple(uint16_t(0x0000), uint8_t(0x55)),
|
||||
std::make_tuple(uint16_t(0x0000), uint8_t(0xAA)),
|
||||
std::make_tuple(uint16_t(0x0000), uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0x5555), uint8_t(0x01)),
|
||||
std::make_tuple(uint16_t(0x5555), uint8_t(0x55)),
|
||||
std::make_tuple(uint16_t(0x5555), uint8_t(0xAA)),
|
||||
std::make_tuple(uint16_t(0x5555), uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint8_t(0x01)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint8_t(0x55)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint8_t(0xAA)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0x8000), uint8_t(0x01)),
|
||||
std::make_tuple(uint16_t(0x8000), uint8_t(0x55)),
|
||||
std::make_tuple(uint16_t(0x8000), uint8_t(0xAA)),
|
||||
std::make_tuple(uint16_t(0x8000), uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint8_t(0x01)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint8_t(0x55)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint8_t(0xAA)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint8_t(0x01)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint8_t(0x55)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint8_t(0xAA)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint8_t(0xFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x0000), simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x0000), simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x0000), simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x0000), simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x0000), simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x0000), simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::bit::one)
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), 00000000000000000001_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x0000), 01010101010101010101_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x0000), 10101010101010101010_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x0000), 11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x5555), 00000000000000000001_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x5555), 01010101010101010101_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x5555), 10101010101010101010_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x5555), 11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x7FFF), 00000000000000000001_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x7FFF), 01010101010101010101_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x7FFF), 10101010101010101010_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x7FFF), 11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x8000), 00000000000000000001_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x8000), 01010101010101010101_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x8000), 10101010101010101010_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x8000), 11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xAAAA), 00000000000000000001_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xAAAA), 01010101010101010101_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xAAAA), 10101010101010101010_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xAAAA), 11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xFFFF), 00000000000000000001_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xFFFF), 01010101010101010101_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xFFFF), 10101010101010101010_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xFFFF), 11111111111111111111_bitstring_8)
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0x0000), 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0x0000), 101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0x0000), 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), 101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), 101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), 101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), 101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), 010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), 101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring)
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(custom_input_type(0x0000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(custom_input_type(0x0000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(custom_input_type(0x0000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(custom_input_type(0x0000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0x5555), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(custom_input_type(0x5555), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(custom_input_type(0x5555), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(custom_input_type(0x5555), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0x7FFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(custom_input_type(0x7FFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(custom_input_type(0x7FFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(custom_input_type(0x7FFF), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0x8000), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(custom_input_type(0x8000), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(custom_input_type(0x8000), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(custom_input_type(0x8000), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0xAAAA), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(custom_input_type(0xAAAA), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(custom_input_type(0xAAAA), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(custom_input_type(0xAAAA), uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0xFFFF), uint64_t(0x0000000000000001)),
|
||||
std::make_tuple(custom_input_type(0xFFFF), uint64_t(0x5555555555555555)),
|
||||
std::make_tuple(custom_input_type(0xFFFF), uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
std::make_tuple(custom_input_type(0xFFFF), uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_small(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_small(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_small(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_small(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_small(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_small(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_small(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_small(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_small(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_small(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_small(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_small(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_plus_minus(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_plus_minus(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_plus_minus(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_plus_minus(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_plus_minus(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_plus_minus(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_xor(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_xor(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_xor(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_xor(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_xor(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_xor(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_xor(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_xor(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_xor(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_xor(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_xor(uint64_t(0x0000000000000001))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_xor(uint64_t(0x5555555555555555))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LIBDPF_TEST_TESTS_HELPERS_EVAL_COMMON_DATA_HPP__
|
||||
798
test/tests/helpers/eval_common_multi_data.hpp
Normal file
798
test/tests/helpers/eval_common_multi_data.hpp
Normal file
|
|
@ -0,0 +1,798 @@
|
|||
#ifndef LIBDPF_TEST_TESTS_HELPERS_EVAL_COMMON_MULTI_DATA_HPP__
|
||||
#define LIBDPF_TEST_TESTS_HELPERS_EVAL_COMMON_MULTI_DATA_HPP__
|
||||
|
||||
#include "custom_input_type.hpp"
|
||||
#include "custom_output_type_small.hpp"
|
||||
#include "custom_output_type_large_plus_minus.hpp"
|
||||
#include "custom_output_type_large_xor.hpp"
|
||||
#include "domain_walk.hpp"
|
||||
|
||||
template <typename InputT,
|
||||
typename OutputT>
|
||||
using test_type = std::tuple<InputT, OutputT, OutputT, OutputT, OutputT>;
|
||||
|
||||
template <typename InputT,
|
||||
typename OutputT>
|
||||
using param_type = std::vector<test_type<InputT, OutputT>>;
|
||||
|
||||
template <typename InputT,
|
||||
typename OutputT0,
|
||||
typename OutputT1,
|
||||
typename OutputT2,
|
||||
typename OutputT3>
|
||||
using multi_test_type = std::tuple<InputT, OutputT0, OutputT1, OutputT2, OutputT3>;
|
||||
|
||||
template <typename InputT,
|
||||
typename OutputT0,
|
||||
typename OutputT1,
|
||||
typename OutputT2,
|
||||
typename OutputT3>
|
||||
using multi_param_type = std::vector<multi_test_type<InputT, OutputT0, OutputT1, OutputT2, OutputT3>>;
|
||||
|
||||
using dpf::literals::operator""_bitstring;
|
||||
using dpf::literals::operator""_bitstring_8;
|
||||
|
||||
static std::tuple
|
||||
<
|
||||
// base test
|
||||
param_type<uint16_t, uint64_t>,
|
||||
|
||||
// test input types
|
||||
param_type<int16_t, uint64_t>,
|
||||
param_type<uint8_t, uint64_t>,
|
||||
param_type<uint64_t, uint64_t>,
|
||||
param_type<simde_int128, uint64_t>,
|
||||
param_type<simde_uint128, uint64_t>,
|
||||
param_type<dpf::bitstring<10>, uint64_t>,
|
||||
param_type<dpf::keyword<3, dpf::alphabets::hex>, uint64_t>,
|
||||
param_type<dpf::modint<10>, uint64_t>,
|
||||
param_type<dpf::xor_wrapper<int16_t>, uint64_t>,
|
||||
param_type<dpf::xor_wrapper<uint16_t>, uint64_t>,
|
||||
|
||||
// test output types
|
||||
param_type<uint16_t, int64_t>,
|
||||
param_type<uint16_t, uint8_t>,
|
||||
param_type<uint16_t, simde_int128>,
|
||||
param_type<uint16_t, simde_uint128>,
|
||||
param_type<uint16_t, dpf::bit>,
|
||||
param_type<uint16_t, dpf::bitstring<20, uint8_t>>,
|
||||
param_type<uint16_t, dpf::bitstring<150>>,
|
||||
param_type<uint16_t, dpf::xor_wrapper<int64_t>>,
|
||||
param_type<uint16_t, dpf::xor_wrapper<uint64_t>>,
|
||||
|
||||
// custom types
|
||||
param_type<custom_input_type, uint64_t>,
|
||||
param_type<uint16_t, custom_output_type_small>,
|
||||
param_type<uint16_t, custom_output_type_large_plus_minus>,
|
||||
param_type<uint16_t, custom_output_type_large_xor>,
|
||||
|
||||
// distinct output types
|
||||
multi_param_type<uint16_t, uint32_t, dpf::xor_wrapper<uint32_t>, dpf::bitstring<20, uint8_t>, dpf::bitstring<32>>
|
||||
> allParams
|
||||
{
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x5555), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0X8000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(int16_t(0x0000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0x5555), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0x7FFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0X8000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0xAAAA), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(int16_t(0xFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint8_t(0x00), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0x55), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0x7F), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0x80), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0xAA), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint8_t(0xFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint64_t(0x0000000000000000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0x5555555555555555), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0x7FFFFFFFFFFFFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0X8000000000000000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0xAAAAAAAAAAAAAAAA), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint64_t(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0x7FFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0x8000000000000000) << 64 | simde_int128(0x0000000000000000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0x7FFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0x8000000000000000) << 64 | simde_uint128(0x0000000000000000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(0000000000_bitstring, uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(0101010101_bitstring, uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(0111111111_bitstring, uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(1000000000_bitstring, uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(1010101010_bitstring, uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(1111111111_bitstring, uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("000"), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("555"), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("7ff"), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("800"), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("aaa"), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::keyword<3, dpf::alphabets::hex>("fff"), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(dpf::modint<10>(0x000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x155), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x1FF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x200), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x2AA), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::modint<10>(0x3FF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
},
|
||||
{
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x0000)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x5555)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x7FFF)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0x8000)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xAAAA)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<int16_t>(int16_t(0xFFFF)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x0000)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x5555)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x7FFF)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0x8000)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xAAAA)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(dpf::xor_wrapper<uint16_t>(uint16_t(0xFFFF)), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), int64_t(0x0000000000000001),
|
||||
int64_t(0x5555555555555555),
|
||||
int64_t(0xAAAAAAAAAAAAAAAA),
|
||||
int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x5555), int64_t(0x0000000000000001),
|
||||
int64_t(0x5555555555555555),
|
||||
int64_t(0xAAAAAAAAAAAAAAAA),
|
||||
int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), int64_t(0x0000000000000001),
|
||||
int64_t(0x5555555555555555),
|
||||
int64_t(0xAAAAAAAAAAAAAAAA),
|
||||
int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0X8000), int64_t(0x0000000000000001),
|
||||
int64_t(0x5555555555555555),
|
||||
int64_t(0xAAAAAAAAAAAAAAAA),
|
||||
int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), int64_t(0x0000000000000001),
|
||||
int64_t(0x5555555555555555),
|
||||
int64_t(0xAAAAAAAAAAAAAAAA),
|
||||
int64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), int64_t(0x0000000000000001),
|
||||
int64_t(0x5555555555555555),
|
||||
int64_t(0xAAAAAAAAAAAAAAAA),
|
||||
int64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), uint8_t(0x01),
|
||||
uint8_t(0x55),
|
||||
uint8_t(0xAA),
|
||||
uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0x5555), uint8_t(0x01),
|
||||
uint8_t(0x55),
|
||||
uint8_t(0xAA),
|
||||
uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint8_t(0x01),
|
||||
uint8_t(0x55),
|
||||
uint8_t(0xAA),
|
||||
uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0x8000), uint8_t(0x01),
|
||||
uint8_t(0x55),
|
||||
uint8_t(0xAA),
|
||||
uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint8_t(0x01),
|
||||
uint8_t(0x55),
|
||||
uint8_t(0xAA),
|
||||
uint8_t(0xFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint8_t(0x01),
|
||||
uint8_t(0x55),
|
||||
uint8_t(0xAA),
|
||||
uint8_t(0xFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001),
|
||||
simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555),
|
||||
simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001),
|
||||
simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555),
|
||||
simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001),
|
||||
simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555),
|
||||
simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001),
|
||||
simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555),
|
||||
simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001),
|
||||
simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555),
|
||||
simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_int128(0x0000000000000000) << 64 | simde_int128(0x0000000000000001),
|
||||
simde_int128(0x5555555555555555) << 64 | simde_int128(0x5555555555555555),
|
||||
simde_int128(0xAAAAAAAAAAAAAAAA) << 64 | simde_int128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_int128(0xFFFFFFFFFFFFFFFF) << 64 | simde_int128(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001),
|
||||
simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555),
|
||||
simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x5555), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001),
|
||||
simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555),
|
||||
simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x7FFF), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001),
|
||||
simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555),
|
||||
simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0x8000), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001),
|
||||
simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555),
|
||||
simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xAAAA), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001),
|
||||
simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555),
|
||||
simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(uint16_t(0xFFFF), simde_uint128(0x0000000000000000) << 64 | simde_uint128(0x0000000000000001),
|
||||
simde_uint128(0x5555555555555555) << 64 | simde_uint128(0x5555555555555555),
|
||||
simde_uint128(0xAAAAAAAAAAAAAAAA) << 64 | simde_uint128(0xAAAAAAAAAAAAAAAA),
|
||||
simde_uint128(0xFFFFFFFFFFFFFFFF) << 64 | simde_uint128(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one,
|
||||
dpf::bit::one)
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), 00000000000000000001_bitstring_8,
|
||||
01010101010101010101_bitstring_8,
|
||||
10101010101010101010_bitstring_8,
|
||||
11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x5555), 00000000000000000001_bitstring_8,
|
||||
01010101010101010101_bitstring_8,
|
||||
10101010101010101010_bitstring_8,
|
||||
11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x7FFF), 00000000000000000001_bitstring_8,
|
||||
01010101010101010101_bitstring_8,
|
||||
10101010101010101010_bitstring_8,
|
||||
11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0x8000), 00000000000000000001_bitstring_8,
|
||||
01010101010101010101_bitstring_8,
|
||||
10101010101010101010_bitstring_8,
|
||||
11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xAAAA), 00000000000000000001_bitstring_8,
|
||||
01010101010101010101_bitstring_8,
|
||||
10101010101010101010_bitstring_8,
|
||||
11111111111111111111_bitstring_8),
|
||||
std::make_tuple(uint16_t(0xFFFF), 00000000000000000001_bitstring_8,
|
||||
01010101010101010101_bitstring_8,
|
||||
10101010101010101010_bitstring_8,
|
||||
11111111111111111111_bitstring_8)
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring,
|
||||
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring,
|
||||
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring,
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring,
|
||||
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring,
|
||||
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring,
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring,
|
||||
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring,
|
||||
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring,
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring,
|
||||
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring,
|
||||
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring,
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring,
|
||||
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring,
|
||||
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring,
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_bitstring,
|
||||
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101_bitstring,
|
||||
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_bitstring,
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_bitstring)
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<int64_t>(int64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<int64_t>(int64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), dpf::xor_wrapper<uint64_t>(uint64_t(0x0000000000000001)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0x5555555555555555)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
dpf::xor_wrapper<uint64_t>(uint64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(custom_input_type(0x0000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0x5555), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0x7FFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0x8000), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0xAAAA), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF)),
|
||||
std::make_tuple(custom_input_type(0xFFFF), uint64_t(0x0000000000000001),
|
||||
uint64_t(0x5555555555555555),
|
||||
uint64_t(0xAAAAAAAAAAAAAAAA),
|
||||
uint64_t(0xFFFFFFFFFFFFFFFF))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_small(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_small(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_small(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_small(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_small(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_small(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_small(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_small(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_small(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_small(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_small(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_small(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_small(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_small(uint64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_plus_minus(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_plus_minus(uint64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), custom_output_type_large_xor(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_xor(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x5555), custom_output_type_large_xor(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_xor(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x7FFF), custom_output_type_large_xor(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_xor(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0x8000), custom_output_type_large_xor(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_xor(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xAAAA), custom_output_type_large_xor(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_xor(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF))),
|
||||
std::make_tuple(uint16_t(0xFFFF), custom_output_type_large_xor(uint64_t(0x0000000000000001)),
|
||||
custom_output_type_large_xor(uint64_t(0x5555555555555555)),
|
||||
custom_output_type_large_xor(uint64_t(0xAAAAAAAAAAAAAAAA)),
|
||||
custom_output_type_large_xor(uint64_t(0xFFFFFFFFFFFFFFFF)))
|
||||
},
|
||||
{
|
||||
std::make_tuple(uint16_t(0x0000), uint32_t(0x00000001),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x00000001)),
|
||||
00000000000000000001_bitstring_8,
|
||||
00000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0x0000), uint32_t(0x55555555),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x55555555)),
|
||||
01010101010101010101_bitstring_8,
|
||||
01010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0x0000), uint32_t(0xAAAAAAAA),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xAAAAAAAA)),
|
||||
10101010101010101010_bitstring_8,
|
||||
10101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0x0000), uint32_t(0xFFFFFFFF),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xFFFFFFFF)),
|
||||
11111111111111111111_bitstring_8,
|
||||
11111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), uint32_t(0x00000001),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x00000001)),
|
||||
00000000000000000001_bitstring_8,
|
||||
00000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), uint32_t(0x55555555),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x55555555)),
|
||||
01010101010101010101_bitstring_8,
|
||||
01010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), uint32_t(0xAAAAAAAA),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xAAAAAAAA)),
|
||||
10101010101010101010_bitstring_8,
|
||||
10101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0x5555), uint32_t(0xFFFFFFFF),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xFFFFFFFF)),
|
||||
11111111111111111111_bitstring_8,
|
||||
11111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint32_t(0x00000001),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x00000001)),
|
||||
00000000000000000001_bitstring_8,
|
||||
00000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint32_t(0x55555555),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x55555555)),
|
||||
01010101010101010101_bitstring_8,
|
||||
01010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint32_t(0xAAAAAAAA),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xAAAAAAAA)),
|
||||
10101010101010101010_bitstring_8,
|
||||
10101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0x7FFF), uint32_t(0xFFFFFFFF),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xFFFFFFFF)),
|
||||
11111111111111111111_bitstring_8,
|
||||
11111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), uint32_t(0x00000001),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x00000001)),
|
||||
00000000000000000001_bitstring_8,
|
||||
00000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), uint32_t(0x55555555),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x55555555)),
|
||||
01010101010101010101_bitstring_8,
|
||||
01010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), uint32_t(0xAAAAAAAA),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xAAAAAAAA)),
|
||||
10101010101010101010_bitstring_8,
|
||||
10101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0x8000), uint32_t(0xFFFFFFFF),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xFFFFFFFF)),
|
||||
11111111111111111111_bitstring_8,
|
||||
11111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint32_t(0x00000001),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x00000001)),
|
||||
00000000000000000001_bitstring_8,
|
||||
00000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint32_t(0x55555555),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x55555555)),
|
||||
01010101010101010101_bitstring_8,
|
||||
01010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint32_t(0xAAAAAAAA),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xAAAAAAAA)),
|
||||
10101010101010101010_bitstring_8,
|
||||
10101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0xAAAA), uint32_t(0xFFFFFFFF),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xFFFFFFFF)),
|
||||
11111111111111111111_bitstring_8,
|
||||
11111111111111111111111111111111_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint32_t(0x00000001),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x00000001)),
|
||||
00000000000000000001_bitstring_8,
|
||||
00000000000000000000000000000001_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint32_t(0x55555555),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0x55555555)),
|
||||
01010101010101010101_bitstring_8,
|
||||
01010101010101010101010101010101_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint32_t(0xAAAAAAAA),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xAAAAAAAA)),
|
||||
10101010101010101010_bitstring_8,
|
||||
10101010101010101010101010101010_bitstring),
|
||||
std::make_tuple(uint16_t(0xFFFF), uint32_t(0xFFFFFFFF),
|
||||
dpf::xor_wrapper<uint32_t>(uint32_t(0xFFFFFFFF)),
|
||||
11111111111111111111_bitstring_8,
|
||||
11111111111111111111111111111111_bitstring)
|
||||
},
|
||||
};
|
||||
|
||||
#endif // LIBDPF_TEST_TESTS_HELPERS_EVAL_COMMON_MULTI_DATA_HPP__
|
||||
65
test/tests/incremental_json_test.cpp
Normal file
65
test/tests/incremental_json_test.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "dpf/json.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Round-trip a comparison-only multi-level key through JSON and confirm the
|
||||
// (public) comparison channel still reconstructs after deserialization.
|
||||
TEST(IncrementalJsonTest, CmpKeyRoundTrips)
|
||||
{
|
||||
const uint32_t alpha = 0x00abcdefu;
|
||||
const uint64_t yt = 42u;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::lt(yt));
|
||||
using KT = std::decay_t<decltype(k0)>;
|
||||
static_assert(KT::is_multilevel, "cmp key must be multi-level");
|
||||
ASSERT_EQ(KT::num_outputs, 0u);
|
||||
|
||||
const std::string s0 = dpf::json::to_json(k0);
|
||||
const std::string s1 = dpf::json::to_json(k1);
|
||||
|
||||
auto r0 = dpf::json::from_json<KT>(s0);
|
||||
auto r1 = dpf::json::from_json<KT>(s1);
|
||||
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
EXPECT_EQ(r0.cmp().nbits, k0.cmp().nbits);
|
||||
EXPECT_EQ(r0.cmp().mask, k0.cmp().mask);
|
||||
EXPECT_EQ(r0.cw_last(), k0.cw_last());
|
||||
EXPECT_EQ(r0.cmp_addend(), k0.cmp_addend());
|
||||
|
||||
auto recon_cmp = [&](uint32_t q) {
|
||||
return dpf::reconstruct(dpf::eval_point(dpf::cmp, r0, q), dpf::eval_point(dpf::cmp, r1, q)) & mask;
|
||||
};
|
||||
EXPECT_EQ(recon_cmp(alpha - 1u), yt);
|
||||
EXPECT_EQ(recon_cmp(0u), yt);
|
||||
EXPECT_EQ(recon_cmp(alpha), 0u);
|
||||
EXPECT_EQ(recon_cmp(alpha + 1u), 0u);
|
||||
}
|
||||
|
||||
// A geq comparison (inverted path-sum) must also survive the round-trip.
|
||||
TEST(IncrementalJsonTest, CmpGeqRoundTrips)
|
||||
{
|
||||
const uint32_t alpha = 100u;
|
||||
const uint64_t yt = 5u, yf = 9u;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::geq(yt, yf));
|
||||
using KT = std::decay_t<decltype(k0)>;
|
||||
|
||||
auto r0 = dpf::json::from_json<KT>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<KT>(dpf::json::to_json(k1));
|
||||
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
auto r = [&](uint32_t q) {
|
||||
return dpf::reconstruct(dpf::eval_point(dpf::cmp, r0, q), dpf::eval_point(dpf::cmp, r1, q)) & mask;
|
||||
};
|
||||
EXPECT_EQ(r(99u), yf);
|
||||
EXPECT_EQ(r(100u), yt);
|
||||
EXPECT_EQ(r(101u), yt);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
1867
test/tests/incremental_test.cpp
Normal file
1867
test/tests/incremental_test.cpp
Normal file
File diff suppressed because it is too large
Load diff
978
test/tests/keyword2_test.cpp
Normal file
978
test/tests/keyword2_test.cpp
Normal file
|
|
@ -0,0 +1,978 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static constexpr char dec4[] = "pad('0')[0-9]{0,4}";
|
||||
static constexpr char dec12[] = "pad('0')[0-9]{1,2}";
|
||||
static constexpr char letters[] = "pad('\\0')[a-z]{0,3}";
|
||||
static constexpr char hex3[] = "pad('0')[0-9a-f]{0,3}";
|
||||
static constexpr char hexfixed[] = "[0-9a-f]{3}";
|
||||
static constexpr char digits4[] = "[0-9]{4}";
|
||||
static constexpr char fields[] = "pad('0')[0-9]{0,2}-pad('0')[0-9]{0,3}";
|
||||
static constexpr char words[] = "[ab]{1,2}";
|
||||
static constexpr char either[] = "cat|car";
|
||||
static constexpr char holes[] = "pad('0')[013]{0,2}";
|
||||
static constexpr char overlap[] = "a|a";
|
||||
static constexpr char ambiguous[] = "(a|ab)(b|)";
|
||||
static constexpr char adjacent[] = "pad('0')[0-9]{0,2}pad('0')[0-9]{0,2}";
|
||||
static constexpr char star[] = "a*";
|
||||
static constexpr char too_long[] = "[a-z]{65}";
|
||||
static constexpr char undelimited[] = "[a-z]{1,3}[a-z]";
|
||||
|
||||
static constexpr char empty_pat[] = "";
|
||||
static constexpr char group_pat[] = "()";
|
||||
static constexpr char a_empty[] = "a()";
|
||||
static constexpr char empty_a[] = "()a";
|
||||
static constexpr char a_empty_b[] = "a()b";
|
||||
static constexpr char padding[] = "padding";
|
||||
static constexpr char lit_star[] = "[*]";
|
||||
static constexpr char lit_plus[] = "[+]";
|
||||
static constexpr char esc_star[] = "\\*";
|
||||
static constexpr char esc_plus[] = "\\+";
|
||||
static constexpr char lit_dot[] = "\\.";
|
||||
static constexpr char lit_q[] = "\\?";
|
||||
static constexpr char lit_lp[] = "\\(";
|
||||
static constexpr char lit_rp[] = "\\)";
|
||||
static constexpr char lit_bar[] = "\\|";
|
||||
static constexpr char lit_lb[] = "\\[";
|
||||
static constexpr char lit_rb[] = "\\]";
|
||||
static constexpr char lit_lc[] = "\\{";
|
||||
static constexpr char lit_rc[] = "\\}";
|
||||
static constexpr char lit_bs[] = "\\\\";
|
||||
static constexpr char lit_n[] = "\\n";
|
||||
static constexpr char lit_t[] = "\\t";
|
||||
static constexpr char lit_r[] = "\\r";
|
||||
static constexpr char lit_A[] = "\\x41";
|
||||
static constexpr char lit_nul[] = "\\x00";
|
||||
static constexpr char lit_sq[] = "\\'";
|
||||
static constexpr char lit_dq[] = "\\\"";
|
||||
static constexpr char lit_dash[] = "\\-";
|
||||
static constexpr char esc_cat[] = "\\n\\t\\x41";
|
||||
static constexpr char cba[] = "[cba]";
|
||||
static constexpr char dupcls[] = "[aab]";
|
||||
static constexpr char dashcls[] = "[a\\-c]";
|
||||
static constexpr char endash[] = "[a-]";
|
||||
static constexpr char bracketcls[] = "[\\]a]";
|
||||
static constexpr char range_esc[] = "[\\x01-\\x03]";
|
||||
static constexpr char dashrange[] = "[--a]";
|
||||
static constexpr char highcls[] = "[\\x7f-\\x81]";
|
||||
static constexpr char negab[] = "[^ab]";
|
||||
static constexpr char dot1[] = ".";
|
||||
static constexpr char dot2[] = ".{2}";
|
||||
static constexpr char dotq[] = ".?";
|
||||
static constexpr char adot[] = "a.";
|
||||
static constexpr char src_alt[] = "c|a|b";
|
||||
static constexpr char a_ab[] = "a|ab";
|
||||
static constexpr char ab_a[] = "ab|a";
|
||||
static constexpr char mid_empty[] = "a||b";
|
||||
static constexpr char lead_empty[] = "|a";
|
||||
static constexpr char trail_empty[] = "a|";
|
||||
static constexpr char nested_alt[] = "(a|bb)(c|dd)";
|
||||
static constexpr char blocks[] = "(a|b)(c|d)";
|
||||
static constexpr char nest_paren[] = "((((a|b))))";
|
||||
static constexpr char opt2[] = "a?b?";
|
||||
static constexpr char opt7[] = "a?b?c?d?e?f?g?";
|
||||
static constexpr char alt_rep[] = "(a|b){2}";
|
||||
static constexpr char alt_opt[] = "(a|b)?";
|
||||
static constexpr char alt_pow[] = "(c|a|b){2}";
|
||||
static constexpr char grp_rep[] = "(ab){0,2}";
|
||||
static constexpr char grp_opt[] = "(ab)?";
|
||||
static constexpr char a_rep[] = "a{2,4}";
|
||||
static constexpr char a01[] = "a{01}";
|
||||
static constexpr char a00[] = "a{0,0}";
|
||||
static constexpr char pad0[] = "pad('0')[0-9]{0}";
|
||||
static constexpr char a63[] = "a{63}";
|
||||
static constexpr char a0_63[] = "a{0,63}";
|
||||
static constexpr char cls_pow8[] = "[ab]{8}";
|
||||
static constexpr char cls_pow9[] = "[ab]{9}";
|
||||
static constexpr char cls_cat[] = "[ab][cd]";
|
||||
static constexpr char xcls[] = "x[ab]";
|
||||
static constexpr char three[] = "[ab]c[de]";
|
||||
static constexpr char cls2[] = "[ab]{2}[ab]";
|
||||
static constexpr char repx[] = "[ab]{0,2}x";
|
||||
static constexpr char varlen[] = "[ab]{1,3}";
|
||||
static constexpr char grp2[] = "(a[bc]){1,2}";
|
||||
static constexpr char abx[] = "(ab|cd){1,2}x";
|
||||
static constexpr char pad_order[] = "pad('0')[a-f0-9]{0,1}";
|
||||
static constexpr char pad_x[] = "pad('x')[ab]{0,2}";
|
||||
static constexpr char pad_sp[] = "pad(' ')[ab]{0,2}";
|
||||
static constexpr char pad_fix[] = "pad('0')[0-9]{2}";
|
||||
static constexpr char pad_fix_x[] = "pad('0')[0-9]{2}x";
|
||||
static constexpr char two_fields[] = "pad('0')[0-9]{0,1}xpad('0')[0-9]{0,1}";
|
||||
static constexpr char pad_quote[] = "pad('\\'')[ab]{0,2}";
|
||||
static constexpr char pad_nl[] = "pad('\\n')[ab]{0,2}";
|
||||
static constexpr char pad_hex[] = "pad('\\x2a')[ab]{0,2}";
|
||||
static constexpr char space_pat[] = "a b";
|
||||
static constexpr char alts53[] =
|
||||
"!|#|$|%|&|,|-|/|0|1|2|3|4|5|6|7|8|9|:|;|<|=|>|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|^|_|`";
|
||||
static constexpr char dots32[] = ".{32}";
|
||||
|
||||
static constexpr char a64[] = "a{64}";
|
||||
static constexpr char a0_64[] = "a{0,64}";
|
||||
static constexpr char a64b[] = "a{64}b";
|
||||
static constexpr char ab32[] = "(ab){32}";
|
||||
static constexpr char ab33[] = "(ab){33}";
|
||||
static constexpr char alts54[] =
|
||||
"!|#|$|%|&|,|-|/|0|1|2|3|4|5|6|7|8|9|:|;|<|=|>|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|^|_|`|a";
|
||||
static constexpr char dots32ab[] = ".{32}[ab]";
|
||||
static constexpr char dots33[] = ".{33}";
|
||||
static constexpr char dot65[] = ".{65}";
|
||||
static constexpr char qempty[] = "()?";
|
||||
static constexpr char deepq[] = "(a?)?";
|
||||
static constexpr char both_empty[] = "(|)";
|
||||
static constexpr char justbar[] = "|";
|
||||
static constexpr char dotora[] = ".|a";
|
||||
static constexpr char classora[] = "[ab]|b";
|
||||
static constexpr char aq[] = "a?|a";
|
||||
static constexpr char padfixd[] = "pad('0')[0-9]{2}[0-9]";
|
||||
static constexpr char varfollow[] = "[ab]{0,1}a";
|
||||
static constexpr char repnull[] = "(a?){1,2}";
|
||||
static constexpr char altnull[] = "(a|){1,2}";
|
||||
static constexpr char quantpad[] = "pad('0')[0-9]{1}{1}";
|
||||
static constexpr char padneg[] = "pad('a')[^b]{0,1}";
|
||||
static constexpr char lohi[] = "a{2,1}";
|
||||
static constexpr char unbounded[] = "a{1,}";
|
||||
static constexpr char fullneg[] = "[^\\x00-\\xff]";
|
||||
static constexpr char plus[] = "a+";
|
||||
static constexpr char emptycls[] = "[]";
|
||||
static constexpr char negempty[] = "[^]";
|
||||
static constexpr char inv[] = "[z-a]";
|
||||
static constexpr char inv_esc[] = "[\\x03-\\x01]";
|
||||
static constexpr char badesc[] = "\\q";
|
||||
static constexpr char badhex[] = "\\xGG";
|
||||
static constexpr char shorthex[] = "\\x1";
|
||||
static constexpr char openp[] = "(a";
|
||||
static constexpr char closep[] = "a)";
|
||||
static constexpr char openb[] = "[a-z";
|
||||
static constexpr char openq[] = "a{1";
|
||||
static constexpr char spaceq[] = "a{1, 2}";
|
||||
static constexpr char padopen[] = "pad(";
|
||||
static constexpr char padempty[] = "pad('')[a]{1}";
|
||||
static constexpr char padnoq[] = "pad('a')[a]";
|
||||
static constexpr char padnoc[] = "pad('a')";
|
||||
static constexpr char aqq[] = "a??";
|
||||
|
||||
#define KW2_A8 "aaaaaaaa"
|
||||
#define KW2_A64 KW2_A8 KW2_A8 KW2_A8 KW2_A8 KW2_A8 KW2_A8 KW2_A8 KW2_A8
|
||||
#define KW2_A512 KW2_A64 KW2_A64 KW2_A64 KW2_A64 KW2_A64 KW2_A64 KW2_A64 KW2_A64
|
||||
static constexpr char lits63[] =
|
||||
KW2_A8 KW2_A8 KW2_A8 KW2_A8 KW2_A8 KW2_A8 KW2_A8 "aaaaaaa";
|
||||
static constexpr char lits64[] = KW2_A64;
|
||||
static constexpr char long_pat[] = KW2_A512 KW2_A512;
|
||||
#undef KW2_A512
|
||||
#undef KW2_A64
|
||||
#undef KW2_A8
|
||||
|
||||
std::size_t bits_for_cardinality(std::uint64_t n)
|
||||
{
|
||||
if (n <= 1) return 1;
|
||||
std::size_t bits = 0;
|
||||
for (auto v = n - 1; v != 0; v >>= 1) ++bits;
|
||||
return bits;
|
||||
}
|
||||
|
||||
std::vector<std::string> class_bytes(std::initializer_list<unsigned char> chars)
|
||||
{
|
||||
std::vector<unsigned char> ordered(chars);
|
||||
std::sort(ordered.begin(), ordered.end());
|
||||
ordered.erase(std::unique(ordered.begin(), ordered.end()), ordered.end());
|
||||
std::vector<std::string> out;
|
||||
for (unsigned char c : ordered) out.emplace_back(1, static_cast<char>(c));
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> byte_span(unsigned lo, unsigned hi)
|
||||
{
|
||||
std::vector<std::string> out;
|
||||
for (unsigned c = lo; c <= hi; ++c) out.emplace_back(1, static_cast<char>(c));
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> negated_bytes(std::initializer_list<unsigned char> excluded)
|
||||
{
|
||||
bool drop[256] = {};
|
||||
for (unsigned char c : excluded) drop[c] = true;
|
||||
std::vector<std::string> out;
|
||||
for (int c = 0; c < 256; ++c)
|
||||
if (!drop[c]) out.emplace_back(1, static_cast<char>(c));
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> concat_lang(const std::vector<std::string> & left,
|
||||
const std::vector<std::string> & right)
|
||||
{
|
||||
std::vector<std::string> out;
|
||||
out.reserve(left.size() * right.size());
|
||||
for (const auto & l : left)
|
||||
for (const auto & r : right)
|
||||
out.push_back(l + r);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> block_lang(std::vector<std::vector<std::string>> parts)
|
||||
{
|
||||
std::vector<std::string> out;
|
||||
for (auto & part : parts)
|
||||
out.insert(out.end(), part.begin(), part.end());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> repeat_lang(const std::vector<std::string> & unit, int lo, int hi)
|
||||
{
|
||||
std::vector<std::string> acc;
|
||||
std::vector<std::string> level{""};
|
||||
for (int k = 0; k <= hi; ++k)
|
||||
{
|
||||
if (k >= lo) acc.insert(acc.end(), level.begin(), level.end());
|
||||
if (k == hi) break;
|
||||
std::vector<std::string> next;
|
||||
next.reserve(level.size() * unit.size());
|
||||
for (const auto & prefix : level)
|
||||
for (const auto & piece : unit)
|
||||
next.push_back(prefix + piece);
|
||||
level.swap(next);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
std::vector<std::string> pad_language(std::string digits, int lo, int hi)
|
||||
{
|
||||
const int radix = static_cast<int>(digits.size());
|
||||
int count = 1;
|
||||
for (int i = 0; i < hi; ++i) count *= radix;
|
||||
std::vector<std::string> out;
|
||||
out.reserve(static_cast<std::size_t>(count));
|
||||
for (int value = 0; value < count; ++value)
|
||||
{
|
||||
std::string raw(static_cast<std::size_t>(hi), digits[0]);
|
||||
int rest = value;
|
||||
for (int i = hi - 1; i >= 0; --i)
|
||||
{
|
||||
raw[static_cast<std::size_t>(i)] = digits[static_cast<std::size_t>(rest % radix)];
|
||||
rest /= radix;
|
||||
}
|
||||
int start = 0;
|
||||
while (start < hi - lo && raw[static_cast<std::size_t>(start)] == digits[0]) ++start;
|
||||
out.push_back(raw.substr(static_cast<std::size_t>(start)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> optional_chain(std::string letters)
|
||||
{
|
||||
const int n = static_cast<int>(letters.size());
|
||||
std::vector<std::string> out;
|
||||
const unsigned total = 1u << n;
|
||||
out.reserve(total);
|
||||
for (unsigned mask = 0; mask < total; ++mask)
|
||||
{
|
||||
std::string spelling;
|
||||
for (int i = 0; i < n; ++i)
|
||||
if ((mask & (1u << (n - 1 - i))) != 0) spelling.push_back(letters[static_cast<std::size_t>(i)]);
|
||||
out.push_back(std::move(spelling));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <const char * Pattern>
|
||||
void expect_language(const std::vector<std::string> & canonical)
|
||||
{
|
||||
using kw = dpf::keyword2<Pattern>;
|
||||
ASSERT_EQ(dpf::keyword2_status<Pattern>(), dpf::keyword2_error::ok);
|
||||
const auto n = static_cast<std::uint64_t>(std::numeric_limits<kw>::max().rank()) + 1;
|
||||
ASSERT_EQ(n, canonical.size());
|
||||
ASSERT_EQ(kw::bits, bits_for_cardinality(n));
|
||||
ASSERT_EQ(dpf::utils::bitlength_of_v<kw>, kw::bits);
|
||||
for (std::uint64_t r = 0; r < n; ++r)
|
||||
{
|
||||
const std::string & spelling = canonical[static_cast<std::size_t>(r)];
|
||||
kw spelled{std::string_view(spelling)};
|
||||
kw ranked = kw::from_rank(static_cast<typename kw::integral_type>(r));
|
||||
EXPECT_EQ(spelled.rank(), r) << spelling;
|
||||
EXPECT_EQ(std::string(ranked), spelling) << r;
|
||||
EXPECT_EQ(spelled, ranked);
|
||||
EXPECT_EQ(dpf::to_string(ranked), spelling);
|
||||
if (r > 0)
|
||||
EXPECT_LT(kw::from_rank(static_cast<typename kw::integral_type>(r - 1)), ranked);
|
||||
}
|
||||
if (!canonical.empty())
|
||||
{
|
||||
EXPECT_EQ(std::string(std::numeric_limits<kw>::min()), canonical.front());
|
||||
EXPECT_EQ(std::string(std::numeric_limits<kw>::max()), canonical.back());
|
||||
EXPECT_EQ(std::numeric_limits<kw>::lowest(), std::numeric_limits<kw>::min());
|
||||
}
|
||||
if (kw::bits < 63 && n < (std::uint64_t{1} << kw::bits))
|
||||
{
|
||||
kw ghost = kw::from_rank(static_cast<typename kw::integral_type>(n));
|
||||
EXPECT_EQ(ghost.rank(), n);
|
||||
EXPECT_GT(ghost, std::numeric_limits<kw>::max());
|
||||
EXPECT_THROW(static_cast<std::string>(ghost), std::domain_error);
|
||||
}
|
||||
}
|
||||
|
||||
template <const char * Pattern>
|
||||
void expect_spellings(std::initializer_list<const char *> spellings)
|
||||
{
|
||||
expect_language<Pattern>(std::vector<std::string>(spellings.begin(), spellings.end()));
|
||||
}
|
||||
|
||||
template <const char * Pattern>
|
||||
void expect_only(std::string text)
|
||||
{
|
||||
expect_language<Pattern>(std::vector<std::string>{std::move(text)});
|
||||
}
|
||||
|
||||
template <const char * Pattern>
|
||||
void expect_status(dpf::keyword2_error error)
|
||||
{
|
||||
EXPECT_EQ(dpf::keyword2_status<Pattern>(), error);
|
||||
}
|
||||
|
||||
template <const char * Pattern>
|
||||
void expect_rejected(std::initializer_list<std::string_view> bad)
|
||||
{
|
||||
using kw = dpf::keyword2<Pattern>;
|
||||
for (std::string_view spelling : bad)
|
||||
EXPECT_THROW(kw{spelling}, std::domain_error) << std::string(spelling);
|
||||
}
|
||||
|
||||
template <const char * Pattern>
|
||||
void roundtrip_language()
|
||||
{
|
||||
using kw = dpf::keyword2<Pattern>;
|
||||
const auto last = std::numeric_limits<kw>::max().rank();
|
||||
const auto count = static_cast<std::uint64_t>(last) + 1;
|
||||
ASSERT_LE(count, 200000u);
|
||||
for (std::uint64_t r = 0; r < count; ++r)
|
||||
{
|
||||
kw key = kw::from_rank(static_cast<typename kw::integral_type>(r));
|
||||
kw back{std::string(key)};
|
||||
ASSERT_EQ(back.rank(), r) << r;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(keyword2, decimal_pad_collapses_leading_zeros)
|
||||
{
|
||||
using kw = dpf::keyword2<dec4>;
|
||||
EXPECT_EQ(kw::bits, 14u);
|
||||
EXPECT_EQ(kw{"7"}.rank(), 7u);
|
||||
EXPECT_EQ(kw{"007"}.rank(), 7u);
|
||||
EXPECT_EQ(kw{""}.rank(), 0u);
|
||||
EXPECT_EQ(kw{"0"}.rank(), 0u);
|
||||
EXPECT_EQ(std::string(kw{"007"}), "7");
|
||||
EXPECT_EQ(std::string(std::numeric_limits<kw>::max()), "9999");
|
||||
EXPECT_THROW(kw{"10000"}, std::domain_error);
|
||||
EXPECT_THROW(kw{"12a"}, std::domain_error);
|
||||
}
|
||||
|
||||
TEST(keyword2, decimal_minimum_width_keeps_a_zero)
|
||||
{
|
||||
using kw = dpf::keyword2<dec12>;
|
||||
EXPECT_EQ(std::string(kw{"0"}), "0");
|
||||
EXPECT_EQ(kw{"00"}.rank(), 0u);
|
||||
EXPECT_EQ(std::string(kw{"00"}), "0");
|
||||
EXPECT_THROW(kw{""}, std::domain_error);
|
||||
}
|
||||
|
||||
TEST(keyword2, nul_pad_matches_legacy_letter_ranks)
|
||||
{
|
||||
using kw = dpf::keyword2<letters>;
|
||||
EXPECT_EQ(kw{"b"}.rank(), 2u);
|
||||
EXPECT_EQ(kw{"aa"}.rank(), 28u);
|
||||
EXPECT_EQ(kw{"cat"}.rank(), 2234u);
|
||||
EXPECT_LT(kw{"b"}.rank(), kw{"aa"}.rank());
|
||||
EXPECT_EQ(std::string(kw{"cat"}), "cat");
|
||||
EXPECT_EQ(kw{std::string_view("\0a", 2)}.rank(), kw{"a"}.rank());
|
||||
}
|
||||
|
||||
TEST(keyword2, hex_pad_versus_fixed_width)
|
||||
{
|
||||
using padded = dpf::keyword2<hex3>;
|
||||
EXPECT_EQ(padded{"a"}.rank(), 10u);
|
||||
EXPECT_EQ(padded{"00a"}.rank(), 10u);
|
||||
EXPECT_EQ(std::string(padded{"00a"}), "a");
|
||||
|
||||
using fixed = dpf::keyword2<hexfixed>;
|
||||
EXPECT_EQ(std::string(fixed{"00a"}), "00a");
|
||||
EXPECT_THROW(fixed{"a"}, std::domain_error);
|
||||
}
|
||||
|
||||
TEST(keyword2, fixed_digits_keep_leading_zeros)
|
||||
{
|
||||
using kw = dpf::keyword2<digits4>;
|
||||
EXPECT_EQ(kw{"0007"}.rank(), 7u);
|
||||
EXPECT_EQ(std::string(kw{"0007"}), "0007");
|
||||
EXPECT_THROW(kw{"7"}, std::domain_error);
|
||||
}
|
||||
|
||||
TEST(keyword2, delimited_pad_fields_share_a_rank)
|
||||
{
|
||||
using kw = dpf::keyword2<fields>;
|
||||
EXPECT_EQ(kw{"7-8"}.rank(), 7008u);
|
||||
EXPECT_EQ(kw{"07-008"}.rank(), 7008u);
|
||||
EXPECT_EQ(std::string(kw{"07-008"}), "7-8");
|
||||
}
|
||||
|
||||
TEST(keyword2, variable_repeat_is_shortlex)
|
||||
{
|
||||
using kw = dpf::keyword2<words>;
|
||||
EXPECT_EQ(std::string(kw::from_rank(0)), "a");
|
||||
EXPECT_EQ(std::string(kw::from_rank(1)), "b");
|
||||
EXPECT_EQ(std::string(kw::from_rank(2)), "aa");
|
||||
EXPECT_LT(kw{"b"}.rank(), kw{"aa"}.rank());
|
||||
}
|
||||
|
||||
TEST(keyword2, alternatives_are_source_order_blocks)
|
||||
{
|
||||
using kw = dpf::keyword2<either>;
|
||||
EXPECT_EQ(std::string(kw{"cat"}), "cat");
|
||||
EXPECT_EQ(std::string(kw{"car"}), "car");
|
||||
EXPECT_LT(kw{"cat"}.rank(), kw{"car"}.rank());
|
||||
}
|
||||
|
||||
TEST(keyword2, pad_digit_order_follows_the_class_text)
|
||||
{
|
||||
using kw = dpf::keyword2<holes>;
|
||||
EXPECT_EQ(kw{"3"}.rank(), 2u);
|
||||
EXPECT_EQ(std::string(kw{"3"}), "3");
|
||||
EXPECT_EQ(kw{"13"}.rank(), 5u);
|
||||
}
|
||||
|
||||
TEST(keyword2, rejected_patterns)
|
||||
{
|
||||
EXPECT_EQ(dpf::keyword2_status<overlap>(), dpf::keyword2_error::overlap);
|
||||
EXPECT_EQ(dpf::keyword2_status<ambiguous>(), dpf::keyword2_error::overlap);
|
||||
EXPECT_EQ(dpf::keyword2_status<adjacent>(), dpf::keyword2_error::delim);
|
||||
EXPECT_EQ(dpf::keyword2_status<undelimited>(), dpf::keyword2_error::delim);
|
||||
EXPECT_EQ(dpf::keyword2_status<star>(), dpf::keyword2_error::syntax);
|
||||
EXPECT_EQ(dpf::keyword2_status<too_long>(), dpf::keyword2_error::length);
|
||||
EXPECT_EQ(dpf::keyword2_status<either>(), dpf::keyword2_error::ok);
|
||||
}
|
||||
|
||||
TEST(keyword2, roundtrip_covers_every_rank)
|
||||
{
|
||||
roundtrip_language<dec12>();
|
||||
roundtrip_language<words>();
|
||||
roundtrip_language<holes>();
|
||||
roundtrip_language<either>();
|
||||
roundtrip_language<fields>();
|
||||
roundtrip_language<dec4>();
|
||||
roundtrip_language<letters>();
|
||||
roundtrip_language<hex3>();
|
||||
roundtrip_language<hexfixed>();
|
||||
roundtrip_language<digits4>();
|
||||
}
|
||||
|
||||
TEST(keyword2, point_query_treats_pad_spellings_as_one_key)
|
||||
{
|
||||
using kw = dpf::keyword2<dec4>;
|
||||
auto [k0, k1] = dpf::make_dpf(kw{"7"}, dpf::bit{1});
|
||||
auto hit = [&](kw point) {
|
||||
return dpf::reconstruct(*dpf::eval_point(k0, point), *dpf::eval_point(k1, point))
|
||||
== dpf::bit::one;
|
||||
};
|
||||
EXPECT_TRUE(hit(kw{"7"}));
|
||||
EXPECT_TRUE(hit(kw{"007"}));
|
||||
EXPECT_FALSE(hit(kw{"42"}));
|
||||
}
|
||||
|
||||
TEST(keyword2, stream_extractor_reports_a_bad_token)
|
||||
{
|
||||
using kw = dpf::keyword2<dec4>;
|
||||
std::stringstream in("007 12a");
|
||||
kw good;
|
||||
ASSERT_TRUE(static_cast<bool>(in >> good));
|
||||
EXPECT_EQ(std::string(good), "7");
|
||||
kw bad;
|
||||
EXPECT_FALSE(static_cast<bool>(in >> bad));
|
||||
}
|
||||
|
||||
TEST(keyword2, literals_and_escapes_are_single_strings)
|
||||
{
|
||||
expect_only<empty_pat>("");
|
||||
expect_only<group_pat>("");
|
||||
expect_only<a_empty>("a");
|
||||
expect_only<empty_a>("a");
|
||||
expect_only<a_empty_b>("ab");
|
||||
expect_only<padding>("padding");
|
||||
expect_only<lit_star>("*");
|
||||
expect_only<lit_plus>("+");
|
||||
expect_only<lit_dot>(".");
|
||||
expect_only<lit_q>("?");
|
||||
expect_only<lit_lp>("(");
|
||||
expect_only<lit_rp>(")");
|
||||
expect_only<lit_bar>("|");
|
||||
expect_only<lit_lb>("[");
|
||||
expect_only<lit_rb>("]");
|
||||
expect_only<lit_lc>("{");
|
||||
expect_only<lit_rc>("}");
|
||||
expect_only<lit_bs>("\\");
|
||||
expect_only<lit_n>("\n");
|
||||
expect_only<lit_t>("\t");
|
||||
expect_only<lit_r>("\r");
|
||||
expect_only<lit_A>("A");
|
||||
expect_only<lit_nul>(std::string(1, '\0'));
|
||||
expect_only<lit_sq>("'");
|
||||
expect_only<lit_dq>("\"");
|
||||
expect_only<lit_dash>("-");
|
||||
expect_only<esc_cat>("\n\tA");
|
||||
expect_only<a01>("a");
|
||||
expect_only<a00>("");
|
||||
expect_only<pad0>("");
|
||||
expect_only<space_pat>("a b");
|
||||
expect_rejected<pad0>({"0", "00"});
|
||||
expect_rejected<a00>({"a"});
|
||||
expect_rejected<space_pat>({"a", "ab", "a b"});
|
||||
}
|
||||
|
||||
TEST(keyword2, classes_rank_by_byte_value)
|
||||
{
|
||||
using kw = dpf::keyword2<cba>;
|
||||
EXPECT_EQ(kw{"a"}.rank(), 0u);
|
||||
EXPECT_EQ(kw{"c"}.rank(), 2u);
|
||||
expect_language<cba>(class_bytes({'c', 'b', 'a'}));
|
||||
expect_language<dupcls>(class_bytes({'a', 'a', 'b'}));
|
||||
expect_language<dashcls>(class_bytes({'a', '-', 'c'}));
|
||||
expect_language<endash>(class_bytes({'a', '-'}));
|
||||
expect_language<bracketcls>(class_bytes({']', 'a'}));
|
||||
expect_language<range_esc>(byte_span(1, 3));
|
||||
expect_language<dashrange>(byte_span(static_cast<unsigned>('-'), static_cast<unsigned>('a')));
|
||||
expect_language<highcls>(byte_span(0x7f, 0x81));
|
||||
expect_rejected<cba>({"", "ab", "d", "A"});
|
||||
}
|
||||
|
||||
TEST(keyword2, dot_and_negated_class_cover_bytes)
|
||||
{
|
||||
expect_language<dot1>(byte_span(0, 255));
|
||||
expect_language<negab>(negated_bytes({'a', 'b'}));
|
||||
expect_rejected<negab>({"a", "b", "", "ab"});
|
||||
|
||||
using dot = dpf::keyword2<dot2>;
|
||||
char pair[] = {1, 2};
|
||||
EXPECT_EQ(dot{std::string_view(pair, 2)}.rank(), 258u);
|
||||
char hi[] = {'\xff', '\xff'};
|
||||
EXPECT_EQ(std::string(dot{std::string_view(hi, 2)}), std::string(hi, hi + 2));
|
||||
EXPECT_EQ(dot::bits, 16u);
|
||||
expect_rejected<dot2>({"", "a", std::string_view(pair, 1)});
|
||||
|
||||
std::vector<std::string> optional{""};
|
||||
for (int b = 0; b < 256; ++b) optional.emplace_back(1, static_cast<char>(b));
|
||||
expect_language<dotq>(optional);
|
||||
using opt = dpf::keyword2<dotq>;
|
||||
EXPECT_EQ(opt{std::string_view("\0", 1)}.rank(), 1u);
|
||||
EXPECT_EQ(std::string(opt::from_rank(256)).size(), 1u);
|
||||
EXPECT_EQ(static_cast<unsigned char>(std::string(opt::from_rank(256))[0]), 255u);
|
||||
|
||||
auto prefixed = concat_lang({"a"}, byte_span(0, 255));
|
||||
expect_language<adot>(prefixed);
|
||||
}
|
||||
|
||||
TEST(keyword2, concatenation_is_mixed_radix_and_alternation_is_source_order)
|
||||
{
|
||||
expect_spellings<src_alt>({"c", "a", "b"});
|
||||
expect_spellings<a_ab>({"a", "ab"});
|
||||
expect_spellings<ab_a>({"ab", "a"});
|
||||
expect_spellings<mid_empty>({"a", "", "b"});
|
||||
expect_spellings<lead_empty>({"", "a"});
|
||||
expect_spellings<trail_empty>({"a", ""});
|
||||
expect_spellings<nested_alt>({"ac", "add", "bbc", "bbdd"});
|
||||
expect_language<blocks>(concat_lang({"a", "b"}, {"c", "d"}));
|
||||
expect_spellings<nest_paren>({"a", "b"});
|
||||
expect_language<cls_cat>(concat_lang({"a", "b"}, {"c", "d"}));
|
||||
expect_spellings<xcls>({"xa", "xb"});
|
||||
expect_spellings<three>({"acd", "ace", "bcd", "bce"});
|
||||
expect_language<alts53>([&] {
|
||||
std::vector<std::string> out;
|
||||
std::string token;
|
||||
for (char c : std::string(alts53))
|
||||
{
|
||||
if (c == '|')
|
||||
{
|
||||
out.push_back(token);
|
||||
token.clear();
|
||||
}
|
||||
else token.push_back(c);
|
||||
}
|
||||
out.push_back(token);
|
||||
return out;
|
||||
}());
|
||||
using alt = dpf::keyword2<alts53>;
|
||||
EXPECT_EQ(alt{"!"}.rank(), 0u);
|
||||
EXPECT_EQ(alt{"0"}.rank(), 8u);
|
||||
EXPECT_EQ(alt{"A"}.rank(), 24u);
|
||||
EXPECT_EQ(std::string(std::numeric_limits<alt>::max()), "`");
|
||||
}
|
||||
|
||||
TEST(keyword2, quantifiers_are_shortlex_and_left_to_right)
|
||||
{
|
||||
expect_language<opt2>(optional_chain("ab"));
|
||||
expect_language<opt7>(optional_chain("abcdefg"));
|
||||
using chain = dpf::keyword2<opt7>;
|
||||
EXPECT_EQ(chain{""}.rank(), 0u);
|
||||
EXPECT_EQ(chain{"g"}.rank(), 1u);
|
||||
EXPECT_EQ(chain{"a"}.rank(), 64u);
|
||||
EXPECT_EQ(chain{"abcdefg"}.rank(), 127u);
|
||||
|
||||
expect_language<alt_rep>(repeat_lang({"a", "b"}, 2, 2));
|
||||
expect_language<alt_opt>(block_lang({{""}, {"a", "b"}}));
|
||||
expect_language<alt_pow>(repeat_lang({"c", "a", "b"}, 2, 2));
|
||||
expect_language<grp_rep>(repeat_lang({"ab"}, 0, 2));
|
||||
expect_spellings<grp_opt>({"", "ab"});
|
||||
expect_spellings<a_rep>({"aa", "aaa", "aaaa"});
|
||||
expect_language<cls2>(repeat_lang({"a", "b"}, 3, 3));
|
||||
expect_language<repx>(concat_lang(repeat_lang({"a", "b"}, 0, 2), {"x"}));
|
||||
expect_language<varlen>(repeat_lang({"a", "b"}, 1, 3));
|
||||
expect_language<grp2>(repeat_lang({"ab", "ac"}, 1, 2));
|
||||
expect_language<abx>(concat_lang(repeat_lang({"ab", "cd"}, 1, 2), {"x"}));
|
||||
expect_language<cls_pow8>(repeat_lang({"a", "b"}, 8, 8));
|
||||
expect_language<cls_pow9>(repeat_lang({"a", "b"}, 9, 9));
|
||||
|
||||
std::vector<std::string> up_to_63;
|
||||
for (int n = 0; n <= 63; ++n) up_to_63.emplace_back(static_cast<std::size_t>(n), 'a');
|
||||
expect_language<a0_63>(up_to_63);
|
||||
expect_only<a63>(std::string(63, 'a'));
|
||||
expect_only<lits63>(std::string(63, 'a'));
|
||||
expect_rejected<a_rep>({"", "a", "aaaaa"});
|
||||
expect_rejected<repx>({"", "a", "aa", "xx"});
|
||||
}
|
||||
|
||||
TEST(keyword2, pad_fields_rank_as_integers_in_written_digit_order)
|
||||
{
|
||||
expect_language<pad_order>(pad_language("0abcdef123456789", 0, 1));
|
||||
expect_language<pad_x>(pad_language("xab", 0, 2));
|
||||
expect_language<pad_sp>(pad_language(" ab", 0, 2));
|
||||
expect_language<pad_fix>(pad_language("0123456789", 2, 2));
|
||||
expect_language<pad_fix_x>(concat_lang(pad_language("0123456789", 2, 2), {"x"}));
|
||||
expect_language<two_fields>(concat_lang(
|
||||
concat_lang(pad_language("0123456789", 0, 1), {"x"}),
|
||||
pad_language("0123456789", 0, 1)));
|
||||
expect_language<pad_quote>(pad_language("'ab", 0, 2));
|
||||
expect_language<pad_nl>(pad_language("\nab", 0, 2));
|
||||
expect_language<pad_hex>(pad_language("*ab", 0, 2));
|
||||
|
||||
using px = dpf::keyword2<pad_x>;
|
||||
EXPECT_EQ(px{"x"}, px{""});
|
||||
EXPECT_EQ(px{"xx"}, px{""});
|
||||
EXPECT_EQ(std::string(px{"xa"}), "a");
|
||||
EXPECT_EQ(std::string(px{"ax"}), "ax");
|
||||
EXPECT_EQ(px{"xa"}.rank(), 1u);
|
||||
|
||||
using pq = dpf::keyword2<pad_quote>;
|
||||
EXPECT_EQ(pq{"'"}, pq{""});
|
||||
EXPECT_EQ(std::string(pq{"'a"}), "a");
|
||||
|
||||
using pn = dpf::keyword2<pad_nl>;
|
||||
EXPECT_EQ(pn{std::string_view("\n", 1)}, pn{""});
|
||||
EXPECT_EQ(std::string(pn{std::string_view("\na", 2)}), "a");
|
||||
|
||||
using ps = dpf::keyword2<pad_sp>;
|
||||
EXPECT_EQ(ps{" "}, ps{""});
|
||||
EXPECT_EQ(std::string(ps{" a"}), "a");
|
||||
|
||||
using pf = dpf::keyword2<pad_fix>;
|
||||
EXPECT_EQ(std::string(pf{"07"}), "07");
|
||||
EXPECT_EQ(pf{"07"}.rank(), 7u);
|
||||
expect_rejected<pad_fix>({"7", "007", "a0"});
|
||||
|
||||
using dec = dpf::keyword2<dec4>;
|
||||
for (int value = 0; value < 10000; ++value)
|
||||
{
|
||||
std::string body = std::to_string(value);
|
||||
std::string padded = std::string(4 - body.size(), '0') + body;
|
||||
std::string canonical = value == 0 ? std::string() : body;
|
||||
EXPECT_EQ(dec{padded}.rank(), static_cast<unsigned>(value));
|
||||
EXPECT_EQ(std::string(dec{padded}), canonical);
|
||||
}
|
||||
|
||||
expect_language<holes>(pad_language("013", 0, 2));
|
||||
}
|
||||
|
||||
TEST(keyword2, syntax_errors_name_the_broken_token)
|
||||
{
|
||||
static_assert(dpf::keyword2_error::ok == dpf::keyword2_error{0});
|
||||
expect_status<star>(dpf::keyword2_error::syntax);
|
||||
expect_status<plus>(dpf::keyword2_error::syntax);
|
||||
expect_status<esc_star>(dpf::keyword2_error::syntax);
|
||||
expect_status<esc_plus>(dpf::keyword2_error::syntax);
|
||||
expect_status<aqq>(dpf::keyword2_error::syntax);
|
||||
expect_status<emptycls>(dpf::keyword2_error::syntax);
|
||||
expect_status<negempty>(dpf::keyword2_error::syntax);
|
||||
expect_status<fullneg>(dpf::keyword2_error::syntax);
|
||||
expect_status<inv>(dpf::keyword2_error::syntax);
|
||||
expect_status<inv_esc>(dpf::keyword2_error::syntax);
|
||||
expect_status<badesc>(dpf::keyword2_error::syntax);
|
||||
expect_status<badhex>(dpf::keyword2_error::syntax);
|
||||
expect_status<shorthex>(dpf::keyword2_error::syntax);
|
||||
expect_status<openp>(dpf::keyword2_error::syntax);
|
||||
expect_status<closep>(dpf::keyword2_error::syntax);
|
||||
expect_status<openb>(dpf::keyword2_error::syntax);
|
||||
expect_status<openq>(dpf::keyword2_error::syntax);
|
||||
expect_status<spaceq>(dpf::keyword2_error::syntax);
|
||||
expect_status<lohi>(dpf::keyword2_error::syntax);
|
||||
expect_status<unbounded>(dpf::keyword2_error::syntax);
|
||||
expect_status<quantpad>(dpf::keyword2_error::syntax);
|
||||
expect_status<padneg>(dpf::keyword2_error::syntax);
|
||||
expect_status<padopen>(dpf::keyword2_error::syntax);
|
||||
expect_status<padempty>(dpf::keyword2_error::syntax);
|
||||
expect_status<padnoq>(dpf::keyword2_error::syntax);
|
||||
expect_status<padnoc>(dpf::keyword2_error::syntax);
|
||||
expect_status<long_pat>(dpf::keyword2_error::syntax);
|
||||
}
|
||||
|
||||
TEST(keyword2, delimiter_and_overlap_errors)
|
||||
{
|
||||
expect_status<adjacent>(dpf::keyword2_error::delim);
|
||||
expect_status<undelimited>(dpf::keyword2_error::delim);
|
||||
expect_status<qempty>(dpf::keyword2_error::delim);
|
||||
expect_status<deepq>(dpf::keyword2_error::delim);
|
||||
expect_status<padfixd>(dpf::keyword2_error::delim);
|
||||
expect_status<varfollow>(dpf::keyword2_error::delim);
|
||||
expect_status<repnull>(dpf::keyword2_error::delim);
|
||||
expect_status<altnull>(dpf::keyword2_error::delim);
|
||||
|
||||
expect_status<overlap>(dpf::keyword2_error::overlap);
|
||||
expect_status<ambiguous>(dpf::keyword2_error::overlap);
|
||||
expect_status<both_empty>(dpf::keyword2_error::overlap);
|
||||
expect_status<justbar>(dpf::keyword2_error::overlap);
|
||||
expect_status<dotora>(dpf::keyword2_error::overlap);
|
||||
expect_status<classora>(dpf::keyword2_error::overlap);
|
||||
expect_status<aq>(dpf::keyword2_error::overlap);
|
||||
}
|
||||
|
||||
TEST(keyword2, length_state_and_width_caps)
|
||||
{
|
||||
expect_status<a64>(dpf::keyword2_error::states);
|
||||
expect_status<a0_64>(dpf::keyword2_error::states);
|
||||
expect_status<ab32>(dpf::keyword2_error::states);
|
||||
expect_status<lits64>(dpf::keyword2_error::states);
|
||||
expect_status<alts54>(dpf::keyword2_error::states);
|
||||
|
||||
expect_status<a64b>(dpf::keyword2_error::length);
|
||||
expect_status<ab33>(dpf::keyword2_error::length);
|
||||
expect_status<too_long>(dpf::keyword2_error::length);
|
||||
expect_status<dot65>(dpf::keyword2_error::length);
|
||||
|
||||
expect_status<dots33>(dpf::keyword2_error::width);
|
||||
expect_status<dots32ab>(dpf::keyword2_error::width);
|
||||
|
||||
using full = dpf::keyword2<dots32>;
|
||||
EXPECT_EQ(dpf::keyword2_status<dots32>(), dpf::keyword2_error::ok);
|
||||
EXPECT_EQ(full::bits, 256u);
|
||||
EXPECT_EQ(std::string(full::from_rank(0)), std::string(32, '\0'));
|
||||
char low[32] = {};
|
||||
low[31] = 5;
|
||||
EXPECT_EQ(full{std::string_view(low, 32)}, full::from_rank(full::integral_type{5}));
|
||||
char high[32] = {};
|
||||
high[0] = 1;
|
||||
EXPECT_GT(full{std::string_view(high, 32)}, full{std::string_view(low, 32)});
|
||||
EXPECT_EQ(std::string(std::numeric_limits<full>::max()), std::string(32, '\xff'));
|
||||
EXPECT_EQ(std::numeric_limits<full>::digits, 256);
|
||||
expect_rejected<dots32>({std::string(31, '\0'), std::string(33, 'a')});
|
||||
}
|
||||
|
||||
TEST(keyword2, values_compare_assign_and_print_as_spellings)
|
||||
{
|
||||
using kw = dpf::keyword2<dec4>;
|
||||
kw original{"42"};
|
||||
kw copy = original;
|
||||
kw moved = std::move(copy);
|
||||
EXPECT_EQ(std::string(moved), "42");
|
||||
EXPECT_EQ(moved, original);
|
||||
kw assigned;
|
||||
EXPECT_EQ(assigned.rank(), 0u);
|
||||
EXPECT_FALSE(static_cast<bool>(assigned));
|
||||
assigned = std::string_view{"007"};
|
||||
EXPECT_EQ(std::string(assigned), "7");
|
||||
EXPECT_TRUE(static_cast<bool>(assigned));
|
||||
assigned = original;
|
||||
EXPECT_EQ(assigned, kw{"42"});
|
||||
EXPECT_EQ(kw{"007"}, kw{"7"});
|
||||
EXPECT_FALSE(kw{"007"} < kw{"7"});
|
||||
EXPECT_LT(kw{"7"}, kw{"42"});
|
||||
EXPECT_EQ(static_cast<kw::integral_type>(kw{"42"}), 42u);
|
||||
|
||||
kw held{"42"};
|
||||
EXPECT_THROW(held = std::string_view{"12a"}, std::domain_error);
|
||||
EXPECT_EQ(std::string(held), "42");
|
||||
|
||||
std::ostringstream printed;
|
||||
printed << dpf::keyword2<hex3>{"00a"};
|
||||
EXPECT_EQ(printed.str(), "a");
|
||||
std::ostringstream empty;
|
||||
empty << kw{""};
|
||||
EXPECT_TRUE(empty.str().empty());
|
||||
|
||||
std::stringstream spaced(" 00a b zz");
|
||||
dpf::keyword2<hex3> hex;
|
||||
ASSERT_TRUE(static_cast<bool>(spaced >> hex));
|
||||
EXPECT_EQ(std::string(hex), "a");
|
||||
ASSERT_TRUE(static_cast<bool>(spaced >> hex));
|
||||
EXPECT_EQ(hex.rank(), 11u);
|
||||
dpf::keyword2<hex3> kept = hex;
|
||||
EXPECT_FALSE(static_cast<bool>(spaced >> kept));
|
||||
EXPECT_EQ(kept, hex);
|
||||
|
||||
std::stringstream retry("zz a");
|
||||
dpf::keyword2<hex3> again{"b"};
|
||||
EXPECT_FALSE(static_cast<bool>(retry >> again));
|
||||
EXPECT_EQ(std::string(again), "b");
|
||||
retry.clear();
|
||||
ASSERT_TRUE(static_cast<bool>(retry >> again));
|
||||
EXPECT_EQ(std::string(again), "a");
|
||||
|
||||
std::stringstream blank(" ");
|
||||
EXPECT_FALSE(static_cast<bool>(blank >> again));
|
||||
EXPECT_EQ(std::string(again), "a");
|
||||
|
||||
using spaced_kw = dpf::keyword2<space_pat>;
|
||||
std::stringstream words_in;
|
||||
words_in << spaced_kw{"a b"};
|
||||
EXPECT_EQ(words_in.str(), "a b");
|
||||
spaced_kw unread{"a b"};
|
||||
EXPECT_FALSE(static_cast<bool>(words_in >> unread));
|
||||
EXPECT_EQ(std::string(unread), "a b");
|
||||
|
||||
using dot = dpf::keyword2<dot2>;
|
||||
char raw[] = {0, 1};
|
||||
EXPECT_EQ(dot{std::string_view(raw, 2)}.rank(), 1u);
|
||||
EXPECT_THROW(dot{"\0\1"}, std::domain_error);
|
||||
|
||||
try
|
||||
{
|
||||
kw{"nope"};
|
||||
FAIL() << "expected domain_error";
|
||||
}
|
||||
catch (const std::domain_error & err)
|
||||
{
|
||||
EXPECT_NE(std::string(err.what()).find("keyword2"), std::string::npos);
|
||||
}
|
||||
try
|
||||
{
|
||||
static_cast<std::string>(kw::from_rank(10000));
|
||||
FAIL() << "expected domain_error";
|
||||
}
|
||||
catch (const std::domain_error & err)
|
||||
{
|
||||
EXPECT_NE(std::string(err.what()).find("outside"), std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(keyword2, numeric_limits_and_bit_utilities_follow_the_rank)
|
||||
{
|
||||
using kw = dpf::keyword2<words>;
|
||||
EXPECT_EQ(kw::bits, 3u);
|
||||
EXPECT_EQ(std::numeric_limits<kw>::digits, 3);
|
||||
EXPECT_EQ(std::numeric_limits<kw>::digits10, 0);
|
||||
EXPECT_EQ(std::numeric_limits<kw>::radix, 2);
|
||||
EXPECT_FALSE(std::numeric_limits<kw>::is_signed);
|
||||
EXPECT_TRUE(std::numeric_limits<kw>::is_integer);
|
||||
EXPECT_TRUE(std::numeric_limits<kw>::is_exact);
|
||||
EXPECT_TRUE(std::numeric_limits<kw>::is_bounded);
|
||||
EXPECT_TRUE(std::numeric_limits<kw>::is_modulo);
|
||||
EXPECT_FALSE(std::numeric_limits<kw>::has_infinity);
|
||||
EXPECT_EQ(std::numeric_limits<kw>::epsilon().rank(), 0u);
|
||||
EXPECT_EQ(std::numeric_limits<kw>::min(), kw{"a"});
|
||||
EXPECT_EQ(std::string(std::numeric_limits<kw>::max()), "bb");
|
||||
EXPECT_EQ(std::numeric_limits<kw const>::digits, 3);
|
||||
EXPECT_EQ(std::numeric_limits<kw volatile>::max(), std::numeric_limits<kw>::max());
|
||||
EXPECT_EQ(std::numeric_limits<kw const volatile>::min(), kw{"a"});
|
||||
|
||||
using dec = dpf::keyword2<dec4>;
|
||||
EXPECT_EQ(std::numeric_limits<dec>::digits, 14);
|
||||
EXPECT_EQ(std::numeric_limits<dec>::digits10, 4);
|
||||
|
||||
EXPECT_EQ(std::string(dpf::utils::msb_of_v<kw>), "ba");
|
||||
EXPECT_EQ(dpf::utils::make_default_v<kw>, kw{"b"});
|
||||
EXPECT_EQ(dpf::utils::make_from_integral_value<kw>{}(4), kw{"ba"});
|
||||
EXPECT_EQ(dpf::utils::to_integral_type<kw>{}(kw{"ba"}), 4u);
|
||||
EXPECT_EQ(dpf::utils::mod_pow_2<kw>{}(kw{"bb"}, 2), 1u);
|
||||
EXPECT_EQ(dpf::utils::countl_zero_symmetric_difference<kw>{}(kw{"a"}, kw{"b"}), 2u);
|
||||
EXPECT_EQ(dpf::utils::countl_zero_symmetric_difference<kw>{}(kw{"aa"}, kw{"aa"}), kw::bits);
|
||||
EXPECT_EQ((~kw{"a"}).rank(), 7u);
|
||||
EXPECT_EQ((~kw::from_rank(7)).rank(), 0u);
|
||||
|
||||
kw cursor = std::numeric_limits<kw>::max();
|
||||
++cursor;
|
||||
EXPECT_EQ(cursor.rank(), 6u);
|
||||
EXPECT_THROW(static_cast<std::string>(cursor), std::domain_error);
|
||||
cursor = kw::from_rank(7);
|
||||
cursor++;
|
||||
EXPECT_EQ(cursor.rank(), 0u);
|
||||
EXPECT_EQ(std::string(cursor), "a");
|
||||
}
|
||||
|
||||
TEST(keyword2, dpf_queries_follow_the_rank)
|
||||
{
|
||||
using kw = dpf::keyword2<cls_pow8>;
|
||||
kw target{"abababab"};
|
||||
ASSERT_EQ(target.rank(), 0b01010101u);
|
||||
auto [k0, k1] = dpf::make_dpf(target, dpf::bit{1});
|
||||
auto memo0 = dpf::make_basic_path_memoizer<std::decay_t<decltype(k0)>>();
|
||||
auto memo1 = dpf::make_basic_path_memoizer<std::decay_t<decltype(k1)>>();
|
||||
|
||||
auto hit = [&](kw point, auto & m0, auto & m1) {
|
||||
return dpf::reconstruct(*dpf::eval_point(k0, point, m0), *dpf::eval_point(k1, point, m1))
|
||||
== dpf::bit::one;
|
||||
};
|
||||
auto plain0 = dpf::make_nonmemoizing_path_memoizer<std::decay_t<decltype(k0)>>();
|
||||
auto plain1 = dpf::make_nonmemoizing_path_memoizer<std::decay_t<decltype(k1)>>();
|
||||
for (unsigned rank = 0; rank < (1u << kw::bits); ++rank)
|
||||
{
|
||||
kw point = kw::from_rank(rank);
|
||||
EXPECT_EQ(hit(point, plain0, plain1), point == target) << rank;
|
||||
EXPECT_EQ(hit(point, memo0, memo1), point == target) << rank;
|
||||
}
|
||||
|
||||
kw from = kw::from_rank(83);
|
||||
kw to = kw::from_rank(87);
|
||||
auto [buf0, iter0] = dpf::eval_interval(k0, from, to);
|
||||
auto [buf1, iter1] = dpf::eval_interval(k1, from, to);
|
||||
auto it0 = iter0.begin();
|
||||
auto it1 = iter1.begin();
|
||||
for (unsigned rank = 83; it0 != iter0.end(); ++rank, ++it0, ++it1)
|
||||
{
|
||||
bool on = static_cast<bool>(*it0) ^ static_cast<bool>(*it1);
|
||||
EXPECT_EQ(on, rank == target.rank()) << rank;
|
||||
}
|
||||
|
||||
auto [full0, full0_iter] = dpf::eval_full(k0);
|
||||
auto [full1, full1_iter] = dpf::eval_full(k1);
|
||||
auto fit0 = full0_iter.begin();
|
||||
auto fit1 = full1_iter.begin();
|
||||
unsigned seen = 0;
|
||||
for (; fit0 != full0_iter.end(); ++seen, ++fit0, ++fit1)
|
||||
{
|
||||
bool on = static_cast<bool>(*fit0) ^ static_cast<bool>(*fit1);
|
||||
EXPECT_EQ(on, seen == target.rank()) << seen;
|
||||
}
|
||||
EXPECT_EQ(seen, 1u << kw::bits);
|
||||
}
|
||||
|
||||
static_assert(dpf::keyword2<src_alt>{"c"}.rank() == 0);
|
||||
static_assert(dpf::keyword2<src_alt>{"a"}.rank() == 1);
|
||||
static_assert(dpf::keyword2<src_alt>{"c"} < dpf::keyword2<src_alt>{"b"});
|
||||
static_assert(dpf::keyword2<dec4>{"007"}.rank() == 7);
|
||||
static_assert(dpf::keyword2<opt2>{""}.rank() == 0);
|
||||
static_assert(dpf::keyword2<opt2>{"ab"}.rank() == 3);
|
||||
static_assert(dpf::keyword2_status<star>() == dpf::keyword2_error::syntax);
|
||||
static_assert(dpf::keyword2_status<overlap>() == dpf::keyword2_error::overlap);
|
||||
static_assert(dpf::keyword2_status<adjacent>() == dpf::keyword2_error::delim);
|
||||
static_assert(dpf::keyword2_status<a64>() == dpf::keyword2_error::states);
|
||||
static_assert(dpf::keyword2_status<a64b>() == dpf::keyword2_error::length);
|
||||
static_assert(dpf::keyword2_status<dots33>() == dpf::keyword2_error::width);
|
||||
static_assert(std::numeric_limits<dpf::keyword2<words>>::max().rank() == 5);
|
||||
static_assert(std::numeric_limits<dpf::keyword2<either>>::min().rank() == 0);
|
||||
510
test/tests/lane_blast_test.cpp
Normal file
510
test/tests/lane_blast_test.cpp
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
simde__m128i g_roots[4];
|
||||
int g_ri = 0;
|
||||
simde__m128i take_root() { return g_roots[g_ri++]; }
|
||||
|
||||
struct Pad
|
||||
{
|
||||
uint64_t n = 1;
|
||||
simde__m128i block()
|
||||
{
|
||||
auto v = simde_mm_set_epi64x(static_cast<long long>(n),
|
||||
static_cast<long long>(n * 5 + 1));
|
||||
n += 2;
|
||||
return v;
|
||||
}
|
||||
uint8_t bit() { return static_cast<uint8_t>(n++ & 1u); }
|
||||
};
|
||||
|
||||
void reset_roots()
|
||||
{
|
||||
g_ri = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
g_roots[i] = simde_mm_set_epi64x(0x1000 * (i + 1), 0xA000u + i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T bare(const T & v) { return v; }
|
||||
|
||||
template <typename T, std::size_t Party, dpf::sharing Scheme>
|
||||
T bare(const dpf::secret_share<T, Party, Scheme> & s) { return s.raw(); }
|
||||
|
||||
template <typename Key, typename In>
|
||||
auto ev(const Key & key, In x)
|
||||
{
|
||||
return bare(*dpf::eval_point(key, x));
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
auto opened(const A & a, const B & b)
|
||||
{
|
||||
if constexpr (dpf::is_secret_share_v<std::decay_t<A>>)
|
||||
return dpf::reconstruct(a, b);
|
||||
else
|
||||
return a - b;
|
||||
}
|
||||
|
||||
unsigned as_u(dpf::twobit v) { return static_cast<unsigned>(v); }
|
||||
unsigned as_u(dpf::nyble v) { return static_cast<unsigned>(v); }
|
||||
unsigned as_u(dpf::bit v) { return static_cast<unsigned>(static_cast<bool>(v)); }
|
||||
|
||||
template <typename Lane>
|
||||
Lane lane_of(unsigned v)
|
||||
{
|
||||
if constexpr (std::is_same_v<Lane, dpf::bit>)
|
||||
return static_cast<dpf::bit>(v & 1u);
|
||||
else if constexpr (std::is_same_v<Lane, dpf::twobit>)
|
||||
return dpf::to_twobit(v);
|
||||
else
|
||||
return dpf::to_nyble(v);
|
||||
}
|
||||
|
||||
template <typename Lane>
|
||||
void expect_share_ring()
|
||||
{
|
||||
constexpr unsigned n = 1u << dpf::utils::packed_lane_bits_v<Lane>;
|
||||
for (unsigned a = 0; a < n; ++a)
|
||||
{
|
||||
for (unsigned b = 0; b < n; ++b)
|
||||
{
|
||||
const Lane av = lane_of<Lane>(a);
|
||||
const Lane bv = lane_of<Lane>(b);
|
||||
auto s0 = dpf::subtractive_share<Lane, 0>::from_raw(av);
|
||||
auto s1 = dpf::subtractive_share<Lane, 1>::from_raw(bv);
|
||||
EXPECT_EQ(dpf::reconstruct(s0, s1), av - bv) << a << " - " << b;
|
||||
|
||||
auto p0 = dpf::additive_share<Lane, 0>::from_raw(av);
|
||||
auto p1 = dpf::additive_share<Lane, 1>::from_raw(bv);
|
||||
EXPECT_EQ(dpf::reconstruct(p0, p1), av + bv);
|
||||
|
||||
auto c0 = s0.as_additive();
|
||||
auto c1 = s1.as_additive();
|
||||
EXPECT_EQ(dpf::reconstruct(c0, c1), dpf::reconstruct(s0, s1));
|
||||
|
||||
// Additive lhs + subtractive rhs. Party 1 subtracts the
|
||||
// foreign share: raw1 = b - b, opened sum is (a+a) + (b-b).
|
||||
auto x0 = p0 + s0;
|
||||
auto x1 = p1 + s1;
|
||||
EXPECT_EQ(x0.raw(), av + av);
|
||||
EXPECT_EQ(x1.raw(), bv - bv);
|
||||
EXPECT_EQ(dpf::reconstruct(x0, x1), (av + av) + (bv - bv));
|
||||
|
||||
auto y0 = s0;
|
||||
auto y1 = s1;
|
||||
y0 += av;
|
||||
y1 += av;
|
||||
EXPECT_EQ(y0.raw(), av + av);
|
||||
EXPECT_EQ(y1.raw(), bv);
|
||||
|
||||
if constexpr (!std::is_same_v<Lane, dpf::bit>)
|
||||
{
|
||||
auto z0 = s0 * bv;
|
||||
EXPECT_EQ(z0.raw(), av * bv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto [z0, z1] = dpf::make_subtractive_shares(lane_of<Lane>(0));
|
||||
EXPECT_EQ(dpf::reconstruct(z0, z1), lane_of<Lane>(0));
|
||||
auto [o0, o1] = dpf::make_subtractive_shares(lane_of<Lane>(1));
|
||||
EXPECT_EQ(dpf::reconstruct(o0, o1), lane_of<Lane>(1));
|
||||
EXPECT_EQ(as_u(o1.raw()), 0u);
|
||||
}
|
||||
|
||||
template <typename In, typename Lane>
|
||||
void expect_every_point(In alpha, Lane y)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
constexpr auto bits = dpf::utils::bitlength_of_v<In>;
|
||||
const uint64_t n = uint64_t{1} << bits;
|
||||
for (uint64_t i = 0; i < n; ++i)
|
||||
{
|
||||
In q;
|
||||
std::memcpy(&q, &i, sizeof(q));
|
||||
const Lane got = opened(ev(k0, q), ev(k1, q));
|
||||
if (q == alpha)
|
||||
EXPECT_EQ(got, y) << "hit " << i;
|
||||
else
|
||||
EXPECT_EQ(got, Lane{}) << "miss " << i;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename In, typename Lane>
|
||||
void expect_interval(In alpha, Lane y, In from, In to)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
auto a = dpf::eval_interval(k0, from, to);
|
||||
auto b = dpf::eval_interval(k1, from, to);
|
||||
auto p0 = std::begin(a.second);
|
||||
auto p1 = std::begin(b.second);
|
||||
for (In q = from; ; ++q)
|
||||
{
|
||||
const Lane got = opened(*p0, *p1);
|
||||
EXPECT_EQ(got, q == alpha ? y : Lane{}) << "interval q";
|
||||
EXPECT_EQ(got, opened(ev(k0, q), ev(k1, q)));
|
||||
++p0;
|
||||
++p1;
|
||||
if (q == to)
|
||||
break;
|
||||
}
|
||||
EXPECT_EQ(p0, std::end(a.second));
|
||||
EXPECT_EQ(p1, std::end(b.second));
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
void expect_live_words(const Key & key, const auto & g)
|
||||
{
|
||||
ASSERT_LE(g.live_levels, g.correction_words.size());
|
||||
for (std::size_t i = 0; i < g.live_levels; ++i)
|
||||
{
|
||||
EXPECT_EQ(std::memcmp(&g.correction_words[i], &key.correction_word(i),
|
||||
sizeof(simde__m128i)), 0) << i;
|
||||
EXPECT_EQ(g.correction_advice[i], key.correction_advice(i)) << i;
|
||||
}
|
||||
if (g.leaf_live)
|
||||
EXPECT_EQ(std::memcmp(&g.leaf, &key.template leaf<0>(), sizeof(g.leaf)), 0);
|
||||
else if (g.live_levels < g.correction_words.size())
|
||||
{
|
||||
EXPECT_NE(std::memcmp(&g.correction_words[g.live_levels],
|
||||
&key.correction_word(g.live_levels), sizeof(simde__m128i)), 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(LaneBlast, ParseStreamsAndLimits)
|
||||
{
|
||||
using namespace dpf::literals::twobit;
|
||||
using namespace dpf::literals::nyble;
|
||||
|
||||
EXPECT_EQ(std::numeric_limits<dpf::twobit>::digits, 2);
|
||||
EXPECT_EQ(std::numeric_limits<dpf::twobit>::min(), dpf::twobit::zero);
|
||||
EXPECT_EQ(std::numeric_limits<dpf::twobit>::max(), dpf::twobit::three);
|
||||
EXPECT_EQ(std::numeric_limits<dpf::nyble>::digits, 4);
|
||||
EXPECT_EQ(std::numeric_limits<dpf::nyble>::max(), dpf::nyble{15});
|
||||
EXPECT_EQ(std::numeric_limits<dpf::nyble>::lowest(), dpf::nyble{0});
|
||||
|
||||
EXPECT_EQ(0_twobit, dpf::twobit::zero);
|
||||
EXPECT_EQ(3_twobit, dpf::twobit::three);
|
||||
EXPECT_EQ(4_twobit, dpf::twobit::zero);
|
||||
EXPECT_EQ(7_twobit, dpf::twobit::three);
|
||||
EXPECT_EQ(15_nyble, dpf::nyble{15});
|
||||
EXPECT_EQ(16_nyble, dpf::nyble{0});
|
||||
EXPECT_EQ(31_nyble, dpf::nyble{15});
|
||||
|
||||
EXPECT_EQ(dpf::to_twobit('0'), dpf::twobit::zero);
|
||||
EXPECT_EQ(dpf::to_twobit('3'), dpf::twobit::three);
|
||||
EXPECT_THROW(dpf::to_twobit('4'), std::domain_error);
|
||||
EXPECT_THROW(dpf::to_twobit('a'), std::domain_error);
|
||||
EXPECT_EQ(dpf::to_nyble('0'), dpf::nyble{0});
|
||||
EXPECT_EQ(dpf::to_nyble('9'), dpf::nyble{9});
|
||||
EXPECT_EQ(dpf::to_nyble('a'), dpf::nyble{10});
|
||||
EXPECT_EQ(dpf::to_nyble('A'), dpf::nyble{10});
|
||||
EXPECT_EQ(dpf::to_nyble('f'), dpf::nyble{15});
|
||||
EXPECT_EQ(dpf::to_nyble('F'), dpf::nyble{15});
|
||||
EXPECT_THROW(dpf::to_nyble('g'), std::domain_error);
|
||||
EXPECT_THROW(dpf::to_nyble('G'), std::domain_error);
|
||||
EXPECT_THROW(dpf::to_nyble('/'), std::domain_error);
|
||||
|
||||
{
|
||||
std::stringstream in("3");
|
||||
dpf::twobit v = dpf::twobit::zero;
|
||||
ASSERT_TRUE(in >> v);
|
||||
EXPECT_EQ(v, dpf::twobit::three);
|
||||
std::stringstream bad("4");
|
||||
ASSERT_FALSE(bad >> v);
|
||||
EXPECT_TRUE(bad.fail());
|
||||
}
|
||||
{
|
||||
std::stringstream in("a");
|
||||
dpf::nyble v{0};
|
||||
ASSERT_TRUE(in >> v);
|
||||
EXPECT_EQ(v, dpf::nyble{10});
|
||||
std::stringstream bad("g");
|
||||
ASSERT_FALSE(bad >> v);
|
||||
EXPECT_TRUE(bad.fail());
|
||||
std::stringstream empty;
|
||||
ASSERT_FALSE(empty >> v);
|
||||
}
|
||||
{
|
||||
std::stringstream out;
|
||||
out << dpf::twobit::two << dpf::nyble{12};
|
||||
EXPECT_EQ(out.str(), "2c");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LaneBlast, ShareWrapsInTheLaneRing)
|
||||
{
|
||||
expect_share_ring<dpf::bit>();
|
||||
expect_share_ring<dpf::twobit>();
|
||||
expect_share_ring<dpf::nyble>();
|
||||
|
||||
auto z0 = dpf::subtractive_share<dpf::twobit, 0>::from_raw(dpf::twobit::zero);
|
||||
auto z1 = dpf::subtractive_share<dpf::twobit, 1>::from_raw(dpf::twobit::one);
|
||||
EXPECT_EQ(dpf::reconstruct(z0, z1), dpf::twobit::three);
|
||||
|
||||
auto n0 = dpf::subtractive_share<dpf::nyble, 0>::from_raw(dpf::nyble{0});
|
||||
auto n1 = dpf::subtractive_share<dpf::nyble, 1>::from_raw(dpf::nyble{1});
|
||||
EXPECT_EQ(dpf::reconstruct(n0, n1), dpf::nyble{15});
|
||||
|
||||
auto b0 = dpf::subtractive_share<dpf::bit, 0>::from_raw(dpf::bit{false});
|
||||
auto b1 = dpf::subtractive_share<dpf::bit, 1>::from_raw(dpf::bit{true});
|
||||
EXPECT_EQ(static_cast<bool>(dpf::reconstruct(b0, b1)), true);
|
||||
}
|
||||
|
||||
TEST(LaneBlast, DepositDoesNotBleedIntoTheNextLane)
|
||||
{
|
||||
simde__m128i node{};
|
||||
dpf::packed::deposit_lane(node, 0, dpf::twobit::three);
|
||||
dpf::packed::deposit_lane(node, 1, dpf::twobit::one);
|
||||
dpf::packed::deposit_lane(node, 2, dpf::twobit::two);
|
||||
dpf::packed::deposit_lane(node, 3, dpf::twobit::zero);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(node, 0), dpf::twobit::three);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(node, 1), dpf::twobit::one);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(node, 2), dpf::twobit::two);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(node, 3), dpf::twobit::zero);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(node, 4), dpf::twobit::zero);
|
||||
|
||||
dpf::packed::deposit_lane(node, 63, dpf::twobit::two);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(node, 63), dpf::twobit::two);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(node, 62), dpf::twobit::zero);
|
||||
|
||||
simde__m256i twos{};
|
||||
dpf::packed::deposit_lane(twos, 127, dpf::twobit::three);
|
||||
dpf::packed::deposit_lane(twos, 126, dpf::twobit::one);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(twos, 127), dpf::twobit::three);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(twos, 126), dpf::twobit::one);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::twobit>(twos, 125), dpf::twobit::zero);
|
||||
|
||||
simde__m256i nibs{};
|
||||
dpf::packed::deposit_lane(nibs, 0, dpf::nyble{0x0f});
|
||||
dpf::packed::deposit_lane(nibs, 1, dpf::nyble{0x01});
|
||||
dpf::packed::deposit_lane(nibs, 63, dpf::nyble{0x0a});
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::nyble>(nibs, 0), dpf::nyble{0x0f});
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::nyble>(nibs, 1), dpf::nyble{0x01});
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::nyble>(nibs, 2), dpf::nyble{0});
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::nyble>(nibs, 63), dpf::nyble{0x0a});
|
||||
EXPECT_EQ(dpf::packed::extract_lane<dpf::nyble>(nibs, 62), dpf::nyble{0});
|
||||
}
|
||||
|
||||
TEST(LaneBlast, Uint8TwobitEveryInputAndEveryShape)
|
||||
{
|
||||
using in_t = uint8_t;
|
||||
using out_t = dpf::twobit;
|
||||
const out_t y = dpf::twobit::three;
|
||||
for (in_t alpha : {in_t{0}, in_t{1}, in_t{63}, in_t{64}, in_t{127}, in_t{128}, in_t{255}})
|
||||
expect_every_point(alpha, y);
|
||||
|
||||
expect_interval<in_t, out_t>(40, y, 40, 40);
|
||||
expect_interval<in_t, out_t>(40, y, 0, 255);
|
||||
expect_interval<in_t, out_t>(0, y, 1, 63);
|
||||
expect_interval<in_t, out_t>(64, dpf::twobit::one, 65, 70);
|
||||
expect_interval<in_t, out_t>(255, dpf::twobit::two, 192, 255);
|
||||
|
||||
auto [k0, k1] = dpf::make_dpf(in_t{40}, y);
|
||||
auto [fb0, fi0] = dpf::eval_full(k0);
|
||||
auto [fb1, fi1] = dpf::eval_full(k1);
|
||||
auto f0 = std::begin(fi0);
|
||||
auto f1 = std::begin(fi1);
|
||||
for (int q = 0; q < 256; ++q, ++f0, ++f1)
|
||||
{
|
||||
EXPECT_EQ(opened(*f0, *f1), q == 40 ? y : out_t{}) << q;
|
||||
}
|
||||
EXPECT_EQ(f0, std::end(fi0));
|
||||
|
||||
const in_t unsorted[] = {255, 40, 0};
|
||||
EXPECT_THROW(dpf::make_sequence_recipe(k0, std::begin(unsorted), std::end(unsorted)),
|
||||
std::runtime_error);
|
||||
const in_t seq[] = {0, 40, 40, 41, 104, 255};
|
||||
auto recipe = dpf::make_sequence_recipe(k0, std::begin(seq), std::end(seq));
|
||||
auto s0 = dpf::eval_sequence(k0, recipe);
|
||||
auto s1 = dpf::eval_sequence(k1, recipe);
|
||||
auto p0 = std::begin(s0.second);
|
||||
auto p1 = std::begin(s1.second);
|
||||
for (in_t q : seq)
|
||||
{
|
||||
EXPECT_EQ(opened(*p0, *p1), q == 40 ? y : out_t{}) << int(q);
|
||||
++p0;
|
||||
++p1;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LaneBlast, Uint8NybleAndBitSameShapes)
|
||||
{
|
||||
using in_t = uint8_t;
|
||||
expect_every_point<in_t>(in_t{0}, dpf::nyble{0});
|
||||
expect_every_point<in_t>(in_t{31}, dpf::nyble{15});
|
||||
expect_every_point<in_t>(in_t{32}, dpf::nyble{1});
|
||||
expect_every_point<in_t>(in_t{255}, dpf::nyble{10});
|
||||
expect_interval<in_t>(in_t{31}, dpf::nyble{15}, in_t{0}, in_t{30});
|
||||
expect_interval<in_t>(in_t{31}, dpf::nyble{15}, in_t{32}, in_t{63});
|
||||
expect_every_point<in_t>(in_t{0}, dpf::bit::one);
|
||||
expect_every_point<in_t>(in_t{127}, dpf::bit::one);
|
||||
expect_every_point<in_t>(in_t{128}, dpf::bit{false});
|
||||
expect_interval<in_t>(in_t{128}, dpf::bit::one, in_t{129}, in_t{255});
|
||||
}
|
||||
|
||||
TEST(LaneBlast, SignedInputPackedLeaf)
|
||||
{
|
||||
using in_t = int8_t;
|
||||
const auto y = dpf::twobit::two;
|
||||
for (in_t alpha : {in_t{-128}, in_t{-1}, in_t{0}, in_t{1}, in_t{127}})
|
||||
expect_every_point(alpha, y);
|
||||
expect_interval<in_t>(in_t{-1}, dpf::nyble{15}, in_t{-3}, in_t{3});
|
||||
expect_interval<in_t>(in_t{-128}, dpf::nyble{1}, in_t{-128}, in_t{127});
|
||||
|
||||
auto [k0, k1] = dpf::make_dpf(in_t{-5}, y);
|
||||
auto a = dpf::eval_full(k0);
|
||||
auto b = dpf::eval_full(k1);
|
||||
auto p0 = std::begin(a.second);
|
||||
auto p1 = std::begin(b.second);
|
||||
for (int q = -128; q <= 127; ++q, ++p0, ++p1)
|
||||
{
|
||||
EXPECT_EQ(opened(*p0, *p1),
|
||||
static_cast<in_t>(q) == in_t{-5} ? y : dpf::twobit{}) << q;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LaneBlast, GenevalMatchesKeyOnPackedLanes)
|
||||
{
|
||||
using in_t = uint8_t;
|
||||
using out_t = dpf::twobit;
|
||||
const out_t y = dpf::twobit::three;
|
||||
const in_t alpha = 40;
|
||||
const in_t x0 = 0x11;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf(alpha,
|
||||
dpf::root_sampler_t<dpf::prg::aes128>{take_root}, y);
|
||||
|
||||
reset_roots();
|
||||
auto on = dpf::geneval_point(x0, x1, alpha, dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
expect_live_words(keys.first, on);
|
||||
EXPECT_TRUE(on.leaf_live);
|
||||
EXPECT_EQ(opened(on.party0[0], on.party1[0]), y);
|
||||
EXPECT_EQ(on.party0[0], ev(keys.first, alpha));
|
||||
EXPECT_EQ(on.party1[0], ev(keys.second, alpha));
|
||||
|
||||
const in_t neighbor = static_cast<in_t>(alpha ^ 1u);
|
||||
reset_roots();
|
||||
auto lane = dpf::geneval_point(x0, x1, neighbor,
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
EXPECT_TRUE(lane.leaf_live);
|
||||
expect_live_words(keys.first, lane);
|
||||
EXPECT_EQ(opened(lane.party0[0], lane.party1[0]), out_t{});
|
||||
EXPECT_EQ(lane.party0[0], ev(keys.first, neighbor));
|
||||
|
||||
const in_t far = 200;
|
||||
reset_roots();
|
||||
auto off = dpf::geneval_point(x0, x1, far, dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
EXPECT_FALSE(off.leaf_live);
|
||||
EXPECT_LT(off.live_levels, off.correction_words.size());
|
||||
expect_live_words(keys.first, off);
|
||||
EXPECT_EQ(opened(off.party0[0], off.party1[0]), out_t{});
|
||||
EXPECT_NE(off.party0[0], ev(keys.first, far));
|
||||
|
||||
reset_roots();
|
||||
auto iv = dpf::geneval_interval(x0, x1, in_t{41}, in_t{50},
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
EXPECT_TRUE(iv.leaf_live);
|
||||
expect_live_words(keys.first, iv);
|
||||
ASSERT_EQ(iv.party0.size(), 10u);
|
||||
for (std::size_t i = 0; i < iv.party0.size(); ++i)
|
||||
EXPECT_EQ(opened(iv.party0[i], iv.party1[i]), out_t{});
|
||||
|
||||
reset_roots();
|
||||
auto full = dpf::geneval_full(x0, x1, dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
EXPECT_EQ(full.party0.size(), 256u);
|
||||
EXPECT_TRUE(full.leaf_live);
|
||||
expect_live_words(keys.first, full);
|
||||
for (int q = 0; q < 256; ++q)
|
||||
{
|
||||
EXPECT_EQ(opened(full.party0[q], full.party1[q]),
|
||||
static_cast<in_t>(q) == alpha ? y : out_t{}) << q;
|
||||
EXPECT_EQ(full.party0[q], ev(keys.first, static_cast<in_t>(q)));
|
||||
}
|
||||
|
||||
const in_t seq[] = {0, 255, alpha, neighbor, alpha};
|
||||
reset_roots();
|
||||
auto sq = dpf::geneval_sequence(x0, x1, std::begin(seq), std::end(seq),
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
EXPECT_TRUE(sq.leaf_live);
|
||||
expect_live_words(keys.first, sq);
|
||||
for (std::size_t i = 0; i < 5; ++i)
|
||||
EXPECT_EQ(opened(sq.party0[i], sq.party1[i]), seq[i] == alpha ? y : out_t{});
|
||||
}
|
||||
|
||||
TEST(LaneBlast, GenevalNybleWildcardAndSigned)
|
||||
{
|
||||
using out_t = dpf::nyble;
|
||||
const out_t y{0x0c};
|
||||
|
||||
{
|
||||
using in_t = uint8_t;
|
||||
const in_t secret = 10;
|
||||
const in_t a0 = 200;
|
||||
const in_t a1 = 66;
|
||||
ASSERT_EQ(static_cast<in_t>(a0 + a1), secret);
|
||||
const in_t target = 5;
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf(target,
|
||||
dpf::root_sampler_t<dpf::prg::aes128>{take_root}, y);
|
||||
reset_roots();
|
||||
auto g = dpf::geneval_point(dpf::wildcard_input, a0, a1, secret,
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, [&] { return target; }, y);
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
expect_live_words(keys.first, g);
|
||||
EXPECT_EQ(opened(g.party0[0], g.party1[0]), y);
|
||||
|
||||
reset_roots();
|
||||
auto miss = dpf::geneval_point(dpf::wildcard_input, a0, a1, in_t{250},
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, [&] { return target; }, y);
|
||||
EXPECT_EQ(opened(miss.party0[0], miss.party1[0]), out_t{});
|
||||
expect_live_words(keys.first, miss);
|
||||
}
|
||||
{
|
||||
using in_t = int8_t;
|
||||
const in_t alpha = -20;
|
||||
const in_t x0 = 3;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf(alpha,
|
||||
dpf::root_sampler_t<dpf::prg::aes128>{take_root}, y);
|
||||
reset_roots();
|
||||
auto full = dpf::geneval_full(x0, x1, dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
EXPECT_EQ(full.party0.size(), 256u);
|
||||
EXPECT_TRUE(full.leaf_live);
|
||||
expect_live_words(keys.first, full);
|
||||
constexpr auto to_int = dpf::utils::to_integral_type<in_t>{};
|
||||
for (int q = -128; q <= 127; ++q)
|
||||
{
|
||||
in_t v = static_cast<in_t>(q);
|
||||
const auto i = static_cast<std::size_t>(to_int(v));
|
||||
EXPECT_EQ(opened(full.party0[i], full.party1[i]), v == alpha ? y : out_t{}) << q;
|
||||
EXPECT_EQ(full.party0[i], ev(keys.first, v));
|
||||
}
|
||||
reset_roots();
|
||||
auto iv = dpf::geneval_interval(x0, x1, in_t{-2}, in_t{2},
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
ASSERT_EQ(iv.party0.size(), 5u);
|
||||
for (int q = -2; q <= 2; ++q)
|
||||
{
|
||||
EXPECT_EQ(opened(iv.party0[static_cast<std::size_t>(q + 2)],
|
||||
iv.party1[static_cast<std::size_t>(q + 2)]), out_t{});
|
||||
}
|
||||
}
|
||||
}
|
||||
724
test/tests/offset_horner_test.cpp
Normal file
724
test/tests/offset_horner_test.cpp
Normal file
|
|
@ -0,0 +1,724 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "grotto/offset_horner.hpp"
|
||||
#include "grotto/prefix_parity.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using grotto::offset_horner_group_add;
|
||||
using grotto::offset_horner_group_sub;
|
||||
|
||||
template <typename T>
|
||||
uint64_t lift(T v)
|
||||
{
|
||||
if constexpr (std::is_signed_v<T>)
|
||||
return static_cast<uint64_t>(static_cast<std::int64_t>(v));
|
||||
else
|
||||
return static_cast<uint64_t>(v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int circular_piece(T point, const std::vector<T> & knots)
|
||||
{
|
||||
if (knots.size() <= 1)
|
||||
return 0;
|
||||
for (std::size_t i = 0; i + 1 < knots.size(); ++i)
|
||||
{
|
||||
if (point >= knots[i] && point < knots[i + 1])
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
return static_cast<int>(knots.size() - 1);
|
||||
}
|
||||
|
||||
template <std::size_t Degree>
|
||||
uint64_t power_sum(const std::array<uint64_t, Degree + 1> & a, uint64_t point)
|
||||
{
|
||||
uint64_t acc = 0;
|
||||
uint64_t p = 1;
|
||||
for (std::size_t m = 0; m <= Degree; ++m)
|
||||
{
|
||||
acc += a[m] * p;
|
||||
p *= point;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
template <std::size_t Degree>
|
||||
std::array<uint64_t, Degree + 1> binomial_shift(
|
||||
const std::array<uint64_t, Degree + 1> & a, uint64_t center)
|
||||
{
|
||||
static constexpr uint64_t binom[4][4] = {
|
||||
{1, 0, 0, 0},
|
||||
{1, 1, 0, 0},
|
||||
{1, 2, 1, 0},
|
||||
{1, 3, 3, 1},
|
||||
};
|
||||
std::array<uint64_t, Degree + 1> c{};
|
||||
for (std::size_t m = 0; m <= Degree; ++m)
|
||||
{
|
||||
for (std::size_t k = 0; k <= m; ++k)
|
||||
{
|
||||
uint64_t cmk = 1;
|
||||
for (std::size_t t = 0; t < m - k; ++t)
|
||||
cmk *= center;
|
||||
c[k] += a[m] * binom[m][k] * cmk;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
template <std::size_t Degree, typename T>
|
||||
const std::array<uint64_t, Degree + 1> & coeff_of_wrapped(
|
||||
T center, T eta, const std::vector<T> & knots,
|
||||
const std::vector<std::array<uint64_t, Degree + 1>> & coeff)
|
||||
{
|
||||
struct row
|
||||
{
|
||||
T knot;
|
||||
std::size_t id;
|
||||
};
|
||||
std::vector<row> rows(knots.size());
|
||||
for (std::size_t i = 0; i < knots.size(); ++i)
|
||||
rows[i] = row{offset_horner_group_sub(knots[i], eta), i};
|
||||
std::sort(rows.begin(), rows.end(),
|
||||
[](const row & a, const row & b) { return a.knot < b.knot; });
|
||||
std::vector<T> shifted(rows.size());
|
||||
for (std::size_t i = 0; i < rows.size(); ++i)
|
||||
shifted[i] = rows[i].knot;
|
||||
const int hot = circular_piece(center, shifted);
|
||||
return coeff[rows[static_cast<std::size_t>(hot)].id];
|
||||
}
|
||||
|
||||
template <std::size_t Degree, typename T>
|
||||
uint64_t gold(T center, T eta, const std::vector<T> & knots,
|
||||
const std::vector<std::array<uint64_t, Degree + 1>> & coeff)
|
||||
{
|
||||
const auto & a = coeff_of_wrapped<Degree>(center, eta, knots, coeff);
|
||||
return power_sum<Degree>(a, lift(center) + lift(eta));
|
||||
}
|
||||
|
||||
template <std::size_t Party, std::size_t Degree, typename T>
|
||||
uint64_t party_eval(const grotto::offset_horner_keys<T, Degree> & mat,
|
||||
const std::vector<T> & knots,
|
||||
const std::vector<std::array<uint64_t, Degree + 1>> & coeff, T eta)
|
||||
{
|
||||
return grotto::offset_horner_eval<Party, Degree>(mat, knots, coeff, eta);
|
||||
}
|
||||
|
||||
template <std::size_t Degree, typename T>
|
||||
uint64_t open_eval(const grotto::offset_horner_keys<T, Degree> & mat,
|
||||
const std::vector<T> & knots,
|
||||
const std::vector<std::array<uint64_t, Degree + 1>> & coeff, T eta)
|
||||
{
|
||||
return party_eval<0, Degree>(mat, knots, coeff, eta)
|
||||
+ party_eval<1, Degree>(mat, knots, coeff, eta);
|
||||
}
|
||||
|
||||
template <std::size_t Degree, typename T>
|
||||
std::array<uint64_t, Degree + 1> open_coeffs(
|
||||
const grotto::offset_horner_keys<T, Degree> & mat,
|
||||
const std::vector<T> & knots,
|
||||
const std::vector<std::array<uint64_t, Degree + 1>> & coeff, T eta)
|
||||
{
|
||||
auto a = grotto::offset_horner_coefficient_share<0, Degree>(mat, knots, coeff, eta);
|
||||
auto b = grotto::offset_horner_coefficient_share<1, Degree>(mat, knots, coeff, eta);
|
||||
for (std::size_t k = 0; k <= Degree; ++k)
|
||||
a[k] += b[k];
|
||||
return a;
|
||||
}
|
||||
|
||||
inline std::vector<std::array<uint64_t, 4>> pad3(
|
||||
std::initializer_list<std::initializer_list<uint64_t>> rows)
|
||||
{
|
||||
std::vector<std::array<uint64_t, 4>> out;
|
||||
out.reserve(rows.size());
|
||||
for (const auto & row : rows)
|
||||
{
|
||||
std::array<uint64_t, 4> a{};
|
||||
std::size_t k = 0;
|
||||
for (uint64_t v : row)
|
||||
{
|
||||
if (k >= 4)
|
||||
break;
|
||||
a[k++] = v;
|
||||
}
|
||||
out.push_back(a);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <std::size_t Degree>
|
||||
std::vector<std::array<uint64_t, Degree + 1>> take_degree(
|
||||
const std::vector<std::array<uint64_t, 4>> & rows)
|
||||
{
|
||||
std::vector<std::array<uint64_t, Degree + 1>> out(rows.size());
|
||||
for (std::size_t i = 0; i < rows.size(); ++i)
|
||||
for (std::size_t k = 0; k <= Degree; ++k)
|
||||
out[i][k] = rows[i][k];
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(OffsetHorner, BinomialAgreesWithPowerSum)
|
||||
{
|
||||
const std::array<uint64_t, 4> a{5, 0, 1, 2};
|
||||
const auto c = binomial_shift<3>(a, 3);
|
||||
EXPECT_EQ(c[0], 68u);
|
||||
EXPECT_EQ(c[1], 60u);
|
||||
EXPECT_EQ(c[2], 19u);
|
||||
EXPECT_EQ(c[3], 2u);
|
||||
uint64_t y = 0;
|
||||
uint64_t p = 1;
|
||||
for (uint64_t ck : c)
|
||||
{
|
||||
y += ck * p;
|
||||
p *= 4;
|
||||
}
|
||||
EXPECT_EQ(y, 740u);
|
||||
EXPECT_EQ(power_sum<3>(a, 7), 740u);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, HandCubicAtCenterPlusEta)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const std::vector<uint8_t> knots{0};
|
||||
const auto coeff = take_degree<D>(pad3({{5, 0, 1, 2}}));
|
||||
const uint8_t center = 3;
|
||||
const uint8_t eta = 4;
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), 740u);
|
||||
EXPECT_EQ(grotto::offset_horner_clear<D>(center, knots, coeff, eta), 740u);
|
||||
const auto got = open_coeffs<D>(mat, knots, coeff, eta);
|
||||
const auto want = binomial_shift<D>(coeff[0], lift(center));
|
||||
EXPECT_EQ(got, want);
|
||||
// Each party evaluates from its own shares and the public eta.
|
||||
const uint64_t p0 = party_eval<0, D>(mat, knots, coeff, eta);
|
||||
const uint64_t p1 = party_eval<1, D>(mat, knots, coeff, eta);
|
||||
EXPECT_EQ(p0 + p1, 740u);
|
||||
EXPECT_NE(p0, 740u);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, MultiPieceSelectsWrappedInput)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const std::vector<uint8_t> knots{0, 10, 50};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{1, 0, 0, 0},
|
||||
{0, 2, 0, 0},
|
||||
{7, 0, 0, 1},
|
||||
}));
|
||||
const uint8_t center = 12;
|
||||
const uint8_t eta = 3;
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
const uint64_t want = gold<D>(center, eta, knots, coeff);
|
||||
EXPECT_EQ(want, 30u);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), want);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, UnreducedSumIsNotTheWrappedRepresentative)
|
||||
{
|
||||
constexpr std::size_t D = 1;
|
||||
const std::vector<uint8_t> knots{0, 30, 80};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{0, 1, 0, 0},
|
||||
{0, 2, 0, 0},
|
||||
{9, 0, 0, 0},
|
||||
}));
|
||||
const uint8_t center = 144;
|
||||
const uint8_t eta = 156;
|
||||
const uint8_t wrapped = offset_horner_group_add(center, eta);
|
||||
EXPECT_EQ(wrapped, 44);
|
||||
EXPECT_EQ(lift(center) + lift(eta), 300u);
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
const uint64_t got = open_eval<D>(mat, knots, coeff, eta);
|
||||
EXPECT_EQ(got, gold<D>(center, eta, knots, coeff));
|
||||
EXPECT_EQ(got, 600u);
|
||||
const int piece = circular_piece(wrapped, knots);
|
||||
const uint64_t at_wrapped = power_sum<D>(coeff[static_cast<std::size_t>(piece)], lift(wrapped));
|
||||
EXPECT_EQ(at_wrapped, 88u);
|
||||
EXPECT_NE(got, at_wrapped);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, XPlusRWiring)
|
||||
{
|
||||
constexpr std::size_t D = 2;
|
||||
const std::vector<uint8_t> knots{0, 40, 100};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{3, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{4, 0, 0, 0},
|
||||
}));
|
||||
const uint8_t x = 20;
|
||||
const uint8_t r = 6;
|
||||
const auto q = grotto::offset_horner_at_x_plus_r(x, r);
|
||||
EXPECT_EQ(q.eta, offset_horner_group_sub(x, r));
|
||||
EXPECT_EQ(q.center, offset_horner_group_add(r, r));
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(q.center);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, q.eta), gold<D>(q.center, q.eta, knots, coeff));
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, DegreesZeroOneAndTwo)
|
||||
{
|
||||
const std::vector<uint8_t> knots{0, 20, 40};
|
||||
const auto full = pad3({
|
||||
{4, 0, 0, 0},
|
||||
{1, 3, 0, 0},
|
||||
{2, 0, 5, 0},
|
||||
});
|
||||
const uint8_t center = 25;
|
||||
const uint8_t eta = 7;
|
||||
{
|
||||
constexpr std::size_t D = 0;
|
||||
const auto coeff = take_degree<D>(full);
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), gold<D>(center, eta, knots, coeff));
|
||||
}
|
||||
{
|
||||
constexpr std::size_t D = 1;
|
||||
const auto coeff = take_degree<D>(full);
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), gold<D>(center, eta, knots, coeff));
|
||||
}
|
||||
{
|
||||
constexpr std::size_t D = 2;
|
||||
const auto coeff = take_degree<D>(full);
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), gold<D>(center, eta, knots, coeff));
|
||||
EXPECT_EQ(open_coeffs<D>(mat, knots, coeff, eta),
|
||||
grotto::offset_horner_clear_coefficients<D>(center, knots, coeff, eta));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, WholeDomainAndWrapPiece)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const auto only = take_degree<D>(pad3({{8, 1, 0, 1}}));
|
||||
auto one = grotto::make_offset_horner_keys<uint8_t, D>(uint8_t{200});
|
||||
EXPECT_EQ(open_eval<D>(one, std::vector<uint8_t>{0}, only, uint8_t{9}),
|
||||
gold<D>(uint8_t{200}, uint8_t{9}, std::vector<uint8_t>{0}, only));
|
||||
|
||||
const std::vector<uint8_t> knots{10, 20};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{1, 0, 0, 0},
|
||||
{6, 2, 0, 0},
|
||||
}));
|
||||
for (uint8_t center : {uint8_t{0}, uint8_t{5}, uint8_t{10}, uint8_t{19}, uint8_t{20}, uint8_t{255}})
|
||||
{
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
for (uint8_t eta : {uint8_t{0}, uint8_t{1}, uint8_t{15}, uint8_t{200}})
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), gold<D>(center, eta, knots, coeff))
|
||||
<< "center=" << int(center) << " eta=" << int(eta);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, CenterOrEtaZero)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const std::vector<uint8_t> knots{0, 8, 16, 64, 200};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{1, 2, 3, 4},
|
||||
{5, 0, 1, 0},
|
||||
{0, 0, 0, 1},
|
||||
{9, 9, 0, 0},
|
||||
{2, 0, 0, 0},
|
||||
}));
|
||||
auto at0 = grotto::make_offset_horner_keys<uint8_t, D>(uint8_t{0});
|
||||
EXPECT_EQ(open_eval<D>(at0, knots, coeff, uint8_t{3}), gold<D>(uint8_t{0}, uint8_t{3}, knots, coeff));
|
||||
auto at = grotto::make_offset_horner_keys<uint8_t, D>(uint8_t{70});
|
||||
EXPECT_EQ(open_eval<D>(at, knots, coeff, uint8_t{0}), gold<D>(uint8_t{70}, uint8_t{0}, knots, coeff));
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, NegativeCoefficientsAndSignedDomain)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const std::vector<int8_t> knots{-128, -40, -1, 0, 20, 100};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{uint64_t(-3), 4, 0, 1},
|
||||
{0, uint64_t(-1), 2, 0},
|
||||
{8, 0, 0, 0},
|
||||
{1, 1, 1, 1},
|
||||
{uint64_t(-5), uint64_t(-5), 0, 0},
|
||||
{2, 0, uint64_t(-1), 0},
|
||||
}));
|
||||
const int8_t center = -2;
|
||||
const int8_t eta = -3;
|
||||
auto mat = grotto::make_offset_horner_keys<int8_t, D>(center);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), gold<D>(center, eta, knots, coeff));
|
||||
EXPECT_EQ(open_coeffs<D>(mat, knots, coeff, eta),
|
||||
binomial_shift<D>(coeff_of_wrapped<D>(center, eta, knots, coeff), lift(center)));
|
||||
|
||||
auto at_max = grotto::make_offset_horner_keys<int8_t, D>(int8_t{127});
|
||||
EXPECT_EQ(open_eval<D>(at_max, knots, coeff, int8_t{-4}),
|
||||
gold<D>(int8_t{127}, int8_t{-4}, knots, coeff));
|
||||
auto at_min = grotto::make_offset_horner_keys<int8_t, D>(std::numeric_limits<int8_t>::min());
|
||||
EXPECT_EQ(open_eval<D>(at_min, knots, coeff, int8_t{1}),
|
||||
gold<D>(std::numeric_limits<int8_t>::min(), int8_t{1}, knots, coeff));
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, ShiftedKnotsThatAreNotSortedStillSelect)
|
||||
{
|
||||
constexpr std::size_t D = 2;
|
||||
const std::vector<uint8_t> knots{0, 10, 20};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{1, 0, 0, 0},
|
||||
{0, 3, 0, 0},
|
||||
{0, 0, 2, 0},
|
||||
}));
|
||||
// eta = 5 rotates 0,10,20 to 251,5,15. The walk sees them sorted.
|
||||
const uint8_t eta = 5;
|
||||
for (uint8_t center : {uint8_t{3}, uint8_t{6}, uint8_t{16}, uint8_t{252}})
|
||||
{
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), gold<D>(center, eta, knots, coeff))
|
||||
<< int(center);
|
||||
const uint8_t wrapped = offset_horner_group_add(center, eta);
|
||||
const auto & selected = coeff_of_wrapped<D>(center, eta, knots, coeff);
|
||||
EXPECT_EQ(selected, coeff[static_cast<std::size_t>(circular_piece(wrapped, knots))]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, RingOverflowDiffersFromWideInteger)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const std::vector<uint32_t> knots{0};
|
||||
const std::array<uint64_t, 4> a{0, 0, 0, 1};
|
||||
const auto coeff = std::vector<std::array<uint64_t, 4>>{a};
|
||||
const uint32_t center = 3u << 20;
|
||||
const uint32_t eta = 1u << 20;
|
||||
using u128 = unsigned __int128;
|
||||
const u128 wide = u128(center) + eta;
|
||||
const u128 wide_p = wide * wide * wide;
|
||||
auto mat = grotto::make_offset_horner_keys<uint32_t, D>(center);
|
||||
const uint64_t got = open_eval<D>(mat, knots, coeff, eta);
|
||||
EXPECT_EQ(got, gold<D>(center, eta, knots, coeff));
|
||||
EXPECT_EQ(got, static_cast<uint64_t>(wide_p));
|
||||
EXPECT_NE(wide_p, u128(got));
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, WrapSharesHideThePayload)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const uint8_t center = 9;
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
uint64_t pow = 1;
|
||||
for (std::size_t m = 0; m <= D; ++m)
|
||||
{
|
||||
EXPECT_EQ(mat.wrap_share[m][0] + mat.wrap_share[m][1], pow);
|
||||
if (pow != 0)
|
||||
EXPECT_NE(mat.wrap_share[m][0], pow);
|
||||
pow *= lift(center);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, PowerKeysAreIndependentComparisons)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const uint16_t center = 1000;
|
||||
auto mat = grotto::make_offset_horner_keys<uint16_t, D>(center);
|
||||
const auto & k0 = std::get<0>(mat.keys[0]);
|
||||
const auto & k1 = std::get<0>(mat.keys[1]);
|
||||
EXPECT_NE(std::memcmp(&k0.root(), &k1.root(), sizeof(k0.root())), 0);
|
||||
bool cw_differs = false;
|
||||
const std::size_t depth = std::remove_reference_t<decltype(k0)>::depth;
|
||||
for (std::size_t level = 0; level < depth; ++level)
|
||||
{
|
||||
if (k0.value_cw(level) != k1.value_cw(level))
|
||||
cw_differs = true;
|
||||
}
|
||||
EXPECT_TRUE(cw_differs);
|
||||
EXPECT_EQ(mat.keys.size(), D + 1);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, DegreeZeroMatchesSignRespectingDot)
|
||||
{
|
||||
constexpr std::size_t D = 0;
|
||||
const std::vector<uint8_t> knots{0, 15, 80, 200};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{4, 0, 0, 0},
|
||||
{11, 0, 0, 0},
|
||||
{uint64_t(-2), 0, 0, 0},
|
||||
{9, 0, 0, 0},
|
||||
}));
|
||||
const uint8_t center = 90;
|
||||
const uint8_t eta = 30;
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
|
||||
struct row { uint8_t knot; uint64_t a; };
|
||||
std::vector<row> rows;
|
||||
for (std::size_t i = 0; i < knots.size(); ++i)
|
||||
rows.push_back(row{offset_horner_group_sub(knots[i], eta), coeff[i][0]});
|
||||
std::sort(rows.begin(), rows.end(),
|
||||
[](const row & a, const row & b) { return a.knot < b.knot; });
|
||||
std::array<uint8_t, 4> shifted{};
|
||||
for (std::size_t i = 0; i < rows.size(); ++i)
|
||||
shifted[i] = rows[i].knot;
|
||||
auto unit = dpf::make_dpf(center, dpf::gt(uint64_t{1}));
|
||||
const auto s0 = grotto::signed_segment_parities(std::get<0>(unit), shifted);
|
||||
const auto s1 = grotto::signed_segment_parities(std::get<1>(unit), shifted);
|
||||
uint64_t dot = 0;
|
||||
for (std::size_t i = 0; i < rows.size(); ++i)
|
||||
dot += (s0[i] + s1[i]) * rows[i].a;
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), dot);
|
||||
EXPECT_EQ(dot, gold<D>(center, eta, knots, coeff));
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, AdviceBitSignIsNotACoefficientShare)
|
||||
{
|
||||
const std::vector<uint8_t> knots{0, 10, 40, 90, 140, 200};
|
||||
std::array<uint8_t, 6> ends{};
|
||||
for (std::size_t i = 0; i < knots.size(); ++i)
|
||||
ends[i] = knots[i];
|
||||
const std::array<uint64_t, 6> constants{3, 5, 7, 11, 13, 17};
|
||||
bool saw_negative = false;
|
||||
bool saw_positive = false;
|
||||
for (int alpha = 0; alpha < 256; ++alpha)
|
||||
{
|
||||
const auto a = static_cast<uint8_t>(alpha);
|
||||
auto [k0, k1] = dpf::make_dpf(a, dpf::bit::one);
|
||||
const auto s0 = grotto::segment_parities(k0, ends);
|
||||
const auto s1 = grotto::segment_parities(k1, ends);
|
||||
int sign = 0;
|
||||
int64_t acc = 0;
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const int bit = int(s0[i]) - int(s1[i]);
|
||||
sign += bit;
|
||||
acc += bit * static_cast<int64_t>(constants[i]);
|
||||
}
|
||||
ASSERT_EQ(sign * sign, 1) << alpha;
|
||||
const int64_t corrected = sign * acc;
|
||||
const int hot = circular_piece(a, knots);
|
||||
ASSERT_EQ(corrected, static_cast<int64_t>(constants[static_cast<std::size_t>(hot)])) << alpha;
|
||||
if (sign < 0)
|
||||
{
|
||||
saw_negative = true;
|
||||
EXPECT_EQ(acc, -corrected);
|
||||
}
|
||||
else
|
||||
{
|
||||
saw_positive = true;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(saw_negative);
|
||||
EXPECT_TRUE(saw_positive);
|
||||
|
||||
// The sign-respecting unit payload does not flip.
|
||||
const uint8_t probe = 40;
|
||||
auto cmp = dpf::make_dpf(probe, dpf::gt(uint64_t{1}));
|
||||
const auto p0 = grotto::signed_segment_parities(std::get<0>(cmp), ends);
|
||||
const auto p1 = grotto::signed_segment_parities(std::get<1>(cmp), ends);
|
||||
uint64_t opened = 0;
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
opened += (p0[i] + p1[i]) * constants[i];
|
||||
EXPECT_EQ(opened, constants[static_cast<std::size_t>(circular_piece(probe, knots))]);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, SignRespectingOneHotIsNotTheShiftedCubic)
|
||||
{
|
||||
constexpr std::size_t D = 2;
|
||||
const std::vector<uint8_t> knots{0, 50, 150};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{1, 0, 0, 0},
|
||||
{0, 4, 1, 0},
|
||||
{8, 0, 0, 0},
|
||||
}));
|
||||
const uint8_t center = 10;
|
||||
const uint8_t eta = 60;
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
const uint64_t ours = open_eval<D>(mat, knots, coeff, eta);
|
||||
|
||||
auto unit = dpf::make_dpf(center, dpf::gt(uint64_t{1}));
|
||||
std::array<uint8_t, 3> ends{0, 50, 150};
|
||||
const auto s0 = grotto::signed_segment_parities(std::get<0>(unit), ends);
|
||||
const auto s1 = grotto::signed_segment_parities(std::get<1>(unit), ends);
|
||||
uint64_t const_term = 0;
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
const_term += (s0[i] + s1[i]) * coeff[i][0];
|
||||
// Unit payload, unshifted knots: the piece of `center`, and only its constant.
|
||||
EXPECT_EQ(const_term, 1u);
|
||||
EXPECT_NE(ours, const_term);
|
||||
EXPECT_EQ(ours, gold<D>(center, eta, knots, coeff));
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, PrefixIntoMatchesFixedArray)
|
||||
{
|
||||
const uint8_t alpha = 40;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(uint64_t{7}));
|
||||
const std::array<uint8_t, 5> ends{0, 1, 10, 40, 200};
|
||||
const auto fixed = grotto::signed_prefix_parities(k0, ends);
|
||||
uint64_t into[5] = {};
|
||||
grotto::signed_prefix_parities_into(k0, ends.data(), ends.size(), into);
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
EXPECT_EQ(into[i], fixed[i]);
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const auto one = std::array<uint8_t, 1>{ends[i]};
|
||||
const auto alone0 = grotto::signed_prefix_parities(k0, one);
|
||||
const auto alone1 = grotto::signed_prefix_parities(k1, one);
|
||||
EXPECT_EQ((alone0[0] + alone1[0]) & mask, ends[i] > alpha ? 7u : 0u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, RejectsBadKnots)
|
||||
{
|
||||
constexpr std::size_t D = 1;
|
||||
const auto coeff = take_degree<D>(pad3({{1, 1, 0, 0}, {2, 0, 0, 0}}));
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(uint8_t{1});
|
||||
EXPECT_THROW(open_eval<D>(mat, std::vector<uint8_t>{}, coeff, uint8_t{0}), std::invalid_argument);
|
||||
EXPECT_THROW(open_eval<D>(mat, std::vector<uint8_t>{1, 1}, coeff, uint8_t{0}), std::invalid_argument);
|
||||
EXPECT_THROW(open_eval<D>(mat, std::vector<uint8_t>{3, 2}, coeff, uint8_t{0}), std::invalid_argument);
|
||||
EXPECT_THROW(open_eval<D>(mat, std::vector<uint8_t>{0}, coeff, uint8_t{0}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, ManyPiecesAndRandomUint16)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
std::mt19937 rng(0x0ff5e7u);
|
||||
std::vector<uint16_t> knots;
|
||||
for (uint16_t k = 0; knots.size() < 20; k = static_cast<uint16_t>(k + 1000))
|
||||
knots.push_back(k);
|
||||
std::vector<std::array<uint64_t, D + 1>> coeff(knots.size());
|
||||
for (auto & row : coeff)
|
||||
for (uint64_t & a : row)
|
||||
a = rng();
|
||||
std::uniform_int_distribution<int> dist(0, 65535);
|
||||
for (int trial = 0; trial < 30; ++trial)
|
||||
{
|
||||
const auto center = static_cast<uint16_t>(dist(rng));
|
||||
const auto eta = static_cast<uint16_t>(dist(rng));
|
||||
auto mat = grotto::make_offset_horner_keys<uint16_t, D>(center);
|
||||
EXPECT_EQ(open_eval<D>(mat, knots, coeff, eta), gold<D>(center, eta, knots, coeff))
|
||||
<< trial;
|
||||
EXPECT_EQ(open_coeffs<D>(mat, knots, coeff, eta),
|
||||
binomial_shift<D>(coeff_of_wrapped<D>(center, eta, knots, coeff), lift(center)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, ExhaustiveUint8AgreesWithGoldAndCountsWraps)
|
||||
{
|
||||
constexpr std::size_t D = 2;
|
||||
const std::vector<uint8_t> knots{0, 30, 80, 140, 200};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{1, 2, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{4, 1, 0, 0},
|
||||
{9, 0, 2, 0},
|
||||
{3, 5, 0, 0},
|
||||
}));
|
||||
int point_mismatch = 0;
|
||||
int value_mismatch = 0;
|
||||
int piece_mismatch = 0;
|
||||
for (int c = 0; c < 256; ++c)
|
||||
{
|
||||
const auto center = static_cast<uint8_t>(c);
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
for (int e = 0; e < 256; ++e)
|
||||
{
|
||||
const auto eta = static_cast<uint8_t>(e);
|
||||
const uint64_t got = open_eval<D>(mat, knots, coeff, eta);
|
||||
const uint64_t want = gold<D>(center, eta, knots, coeff);
|
||||
if (got != want)
|
||||
{
|
||||
ADD_FAILURE() << "center=" << c << " eta=" << e
|
||||
<< " got=" << got << " want=" << want;
|
||||
return;
|
||||
}
|
||||
const uint8_t wrapped = offset_horner_group_add(center, eta);
|
||||
const uint64_t unreduced = lift(center) + lift(eta);
|
||||
if (unreduced != lift(wrapped))
|
||||
++point_mismatch;
|
||||
const auto & selected = coeff_of_wrapped<D>(center, eta, knots, coeff);
|
||||
const auto & wrapped_row = coeff[static_cast<std::size_t>(circular_piece(wrapped, knots))];
|
||||
if (selected != wrapped_row)
|
||||
++piece_mismatch;
|
||||
if (power_sum<D>(selected, unreduced) != power_sum<D>(selected, lift(wrapped)))
|
||||
++value_mismatch;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(point_mismatch, 32640);
|
||||
EXPECT_EQ(piece_mismatch, 0);
|
||||
EXPECT_GT(value_mismatch, 0);
|
||||
EXPECT_LT(value_mismatch, 65536);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, ExhaustiveInt8AgreesWithGoldAndCountsOverflows)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
const std::vector<int8_t> knots{-128, -50, -3, 0, 40, 90};
|
||||
const auto coeff = take_degree<D>(pad3({
|
||||
{1, 0, 0, 1},
|
||||
{0, uint64_t(-2), 0, 0},
|
||||
{5, 1, 1, 0},
|
||||
{0, 0, 3, 0},
|
||||
{2, 0, 0, 0},
|
||||
{uint64_t(-4), 1, 0, 1},
|
||||
}));
|
||||
int point_mismatch = 0;
|
||||
int piece_mismatch = 0;
|
||||
for (int c = -128; c <= 127; ++c)
|
||||
{
|
||||
const auto center = static_cast<int8_t>(c);
|
||||
auto mat = grotto::make_offset_horner_keys<int8_t, D>(center);
|
||||
for (int e = -128; e <= 127; ++e)
|
||||
{
|
||||
const auto eta = static_cast<int8_t>(e);
|
||||
const uint64_t got = open_eval<D>(mat, knots, coeff, eta);
|
||||
const uint64_t want = gold<D>(center, eta, knots, coeff);
|
||||
if (got != want)
|
||||
{
|
||||
ADD_FAILURE() << "center=" << c << " eta=" << e
|
||||
<< " got=" << got << " want=" << want;
|
||||
return;
|
||||
}
|
||||
const int8_t wrapped = offset_horner_group_add(center, eta);
|
||||
const uint64_t unreduced = lift(center) + lift(eta);
|
||||
if (unreduced != lift(wrapped))
|
||||
++point_mismatch;
|
||||
const auto & selected = coeff_of_wrapped<D>(center, eta, knots, coeff);
|
||||
const auto & wrapped_row = coeff[static_cast<std::size_t>(circular_piece(wrapped, knots))];
|
||||
if (selected != wrapped_row)
|
||||
++piece_mismatch;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(point_mismatch, 16384);
|
||||
EXPECT_EQ(piece_mismatch, 0);
|
||||
}
|
||||
|
||||
TEST(OffsetHorner, HornerOfOpenedCoefficientsMatchesValue)
|
||||
{
|
||||
constexpr std::size_t D = 3;
|
||||
std::mt19937 rng(1);
|
||||
const std::vector<uint8_t> knots{0, 25, 100, 180};
|
||||
std::vector<std::array<uint64_t, D + 1>> coeff(knots.size());
|
||||
for (auto & row : coeff)
|
||||
for (uint64_t & a : row)
|
||||
a = rng();
|
||||
const uint8_t center = 77;
|
||||
const uint8_t eta = 19;
|
||||
auto mat = grotto::make_offset_horner_keys<uint8_t, D>(center);
|
||||
const auto c = open_coeffs<D>(mat, knots, coeff, eta);
|
||||
uint64_t y = 0;
|
||||
uint64_t p = 1;
|
||||
const uint64_t e = lift(eta);
|
||||
for (uint64_t ck : c)
|
||||
{
|
||||
y += ck * p;
|
||||
p *= e;
|
||||
}
|
||||
EXPECT_EQ(y, open_eval<D>(mat, knots, coeff, eta));
|
||||
EXPECT_EQ(y, gold<D>(center, eta, knots, coeff));
|
||||
}
|
||||
282
test/tests/packed_lane_test.cpp
Normal file
282
test/tests/packed_lane_test.cpp
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "simde/simde/x86/avx2.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <unsigned Bits>
|
||||
unsigned lane_of(unsigned byte, unsigned shift)
|
||||
{
|
||||
return (byte >> shift) & ((1u << Bits) - 1u);
|
||||
}
|
||||
|
||||
template <typename Reg, unsigned Bits, typename Simd>
|
||||
void expect_vv(Simd simd, unsigned (*scalar)(unsigned, unsigned))
|
||||
{
|
||||
constexpr int nbytes = static_cast<int>(sizeof(Reg));
|
||||
constexpr unsigned per = 8u / Bits;
|
||||
for (int a0 = 0; a0 < 256; ++a0)
|
||||
{
|
||||
for (int b0 = 0; b0 < 256; ++b0)
|
||||
{
|
||||
alignas(32) unsigned char ab[32]{};
|
||||
alignas(32) unsigned char bb[32]{};
|
||||
alignas(32) unsigned char cb[32]{};
|
||||
for (int i = 0; i < nbytes; ++i)
|
||||
{
|
||||
ab[i] = static_cast<unsigned char>((a0 + i * 17) & 255);
|
||||
bb[i] = static_cast<unsigned char>((b0 + i * 3) & 255);
|
||||
}
|
||||
Reg a, b, c;
|
||||
std::memcpy(&a, ab, sizeof(Reg));
|
||||
std::memcpy(&b, bb, sizeof(Reg));
|
||||
c = simd(a, b);
|
||||
std::memcpy(cb, &c, sizeof(Reg));
|
||||
for (int i = 0; i < nbytes; ++i)
|
||||
{
|
||||
for (unsigned s = 0; s < per; ++s)
|
||||
{
|
||||
const unsigned shift = s * Bits;
|
||||
const unsigned expect = scalar(
|
||||
lane_of<Bits>(ab[i], shift),
|
||||
lane_of<Bits>(bb[i], shift)) & ((1u << Bits) - 1u);
|
||||
const unsigned got = lane_of<Bits>(cb[i], shift);
|
||||
if (got != expect)
|
||||
{
|
||||
ADD_FAILURE() << "byte " << i << " shift " << shift
|
||||
<< " a0 " << a0 << " b0 " << b0
|
||||
<< " got " << got << " expect " << expect;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Reg, unsigned Bits, typename Simd>
|
||||
void expect_sv(Simd simd)
|
||||
{
|
||||
constexpr int nbytes = static_cast<int>(sizeof(Reg));
|
||||
constexpr unsigned mask = (1u << Bits) - 1u;
|
||||
constexpr unsigned per = 8u / Bits;
|
||||
for (unsigned k = 0; k <= mask; ++k)
|
||||
{
|
||||
alignas(32) unsigned char ab[32]{};
|
||||
alignas(32) unsigned char cb[32]{};
|
||||
for (int i = 0; i < nbytes; ++i)
|
||||
ab[i] = static_cast<unsigned char>(i * 13u + k);
|
||||
Reg a, c;
|
||||
std::memcpy(&a, ab, sizeof(Reg));
|
||||
if constexpr (Bits == 2)
|
||||
c = simd(a, static_cast<dpf::twobit>(k));
|
||||
else
|
||||
c = simd(a, static_cast<dpf::nyble>(k));
|
||||
std::memcpy(cb, &c, sizeof(Reg));
|
||||
for (int i = 0; i < nbytes; ++i)
|
||||
{
|
||||
for (unsigned s = 0; s < per; ++s)
|
||||
{
|
||||
const unsigned shift = s * Bits;
|
||||
const unsigned expect
|
||||
= (lane_of<Bits>(ab[i], shift) * k) & mask;
|
||||
const unsigned got = lane_of<Bits>(cb[i], shift);
|
||||
if (got != expect)
|
||||
{
|
||||
ADD_FAILURE() << "sv byte " << i << " k " << k
|
||||
<< " got " << got << " expect " << expect;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Lane>
|
||||
void check_ring()
|
||||
{
|
||||
constexpr unsigned n = 1u << dpf::utils::packed_lane_bits_v<Lane>;
|
||||
for (unsigned a = 0; a < n; ++a)
|
||||
{
|
||||
for (unsigned b = 0; b < n; ++b)
|
||||
{
|
||||
const auto x = static_cast<Lane>(a);
|
||||
const auto y = static_cast<Lane>(b);
|
||||
EXPECT_EQ(static_cast<unsigned>(x + y), (a + b) & (n - 1u));
|
||||
EXPECT_EQ(static_cast<unsigned>(x - y), (a - b) & (n - 1u));
|
||||
EXPECT_EQ(static_cast<unsigned>(x * y), (a * b) & (n - 1u));
|
||||
EXPECT_EQ(static_cast<unsigned>(x + (x - x)), a);
|
||||
EXPECT_EQ(static_cast<unsigned>(-x), (0u - a) & (n - 1u));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename NodeT, typename Lane>
|
||||
void check_deposit(std::size_t lane)
|
||||
{
|
||||
const auto y = static_cast<Lane>(lane & ((1u << dpf::utils::packed_lane_bits_v<Lane>) - 1u));
|
||||
auto node = dpf::packed::make_lane_node<NodeT>(lane, y);
|
||||
EXPECT_EQ(dpf::packed::extract_lane<Lane>(node, lane), y);
|
||||
if (lane > 0)
|
||||
{
|
||||
EXPECT_EQ(dpf::packed::extract_lane<Lane>(node, lane - 1), Lane{});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Lane>
|
||||
void check_dpf_output(Lane y)
|
||||
{
|
||||
using input_type = std::uint32_t;
|
||||
constexpr input_type x = 40;
|
||||
constexpr input_type n = 96;
|
||||
auto [k0, k1] = dpf::make_dpf(x, y);
|
||||
for (input_type i = 0; i < n; ++i)
|
||||
{
|
||||
const auto got = dpf::reconstruct(
|
||||
*dpf::eval_point(k0, i), *dpf::eval_point(k1, i));
|
||||
EXPECT_EQ(got, i == x ? y : Lane{}) << "point " << i;
|
||||
}
|
||||
|
||||
auto [buf0, it0] = dpf::eval_interval(k0, input_type{0}, input_type{n - 1});
|
||||
auto [buf1, it1] = dpf::eval_interval(k1, input_type{0}, input_type{n - 1});
|
||||
auto p0 = it0.begin();
|
||||
auto p1 = it1.begin();
|
||||
for (input_type i = 0; i < n; ++i, ++p0, ++p1)
|
||||
{
|
||||
EXPECT_EQ(dpf::reconstruct(*p0, *p1), i == x ? y : Lane{})
|
||||
<< "interval " << i;
|
||||
}
|
||||
EXPECT_EQ(p0, it0.end());
|
||||
EXPECT_EQ(p1, it1.end());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(PackedLane, ScalarRing)
|
||||
{
|
||||
using namespace dpf::literals::twobit;
|
||||
using namespace dpf::literals::nyble;
|
||||
|
||||
check_ring<dpf::twobit>();
|
||||
check_ring<dpf::nyble>();
|
||||
EXPECT_EQ(dpf::to_string(dpf::twobit::three), "3");
|
||||
EXPECT_EQ(dpf::to_string(dpf::nyble{0x0a}), "a");
|
||||
EXPECT_EQ(dpf::to_nyble('F'), dpf::nyble{15});
|
||||
EXPECT_EQ(2_twobit, dpf::twobit::two);
|
||||
EXPECT_EQ(10_nyble, dpf::nyble{10});
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<dpf::twobit>, 2u);
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<dpf::nyble>, 4u);
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::twobit, simde__m256i>), 2u);
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::nyble, simde__m128i>), 4u);
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<dpf::twobit, simde__m128i>), 64u);
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<dpf::twobit, simde__m256i>), 128u);
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<dpf::nyble, simde__m128i>), 32u);
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<dpf::nyble, simde__m256i>), 64u);
|
||||
EXPECT_EQ((dpf::lg_outputs_per_leaf_v<dpf::twobit, simde__m256i>), 7u);
|
||||
}
|
||||
|
||||
TEST(PackedLane, SimdMatchesScalar)
|
||||
{
|
||||
auto add2 = [](unsigned a, unsigned b) { return (a + b) & 3u; };
|
||||
auto sub2 = [](unsigned a, unsigned b) { return (a - b) & 3u; };
|
||||
auto mul2 = [](unsigned a, unsigned b) { return (a * b) & 3u; };
|
||||
auto add4 = [](unsigned a, unsigned b) { return (a + b) & 15u; };
|
||||
auto sub4 = [](unsigned a, unsigned b) { return (a - b) & 15u; };
|
||||
auto mul4 = [](unsigned a, unsigned b) { return (a * b) & 15u; };
|
||||
|
||||
expect_vv<simde__m128i, 2>([](auto a, auto b) { return dpf::lane_arith::add_epi2(a, b); }, add2);
|
||||
expect_vv<simde__m256i, 2>([](auto a, auto b) { return dpf::lane_arith::add_epi2(a, b); }, add2);
|
||||
expect_vv<simde__m128i, 2>([](auto a, auto b) { return dpf::lane_arith::sub_epi2(a, b); }, sub2);
|
||||
expect_vv<simde__m256i, 2>([](auto a, auto b) { return dpf::lane_arith::sub_epi2(a, b); }, sub2);
|
||||
expect_vv<simde__m128i, 2>([](auto a, auto b) { return dpf::lane_arith::mullo_epi2(a, b); }, mul2);
|
||||
expect_vv<simde__m256i, 2>([](auto a, auto b) { return dpf::lane_arith::mullo_epi2(a, b); }, mul2);
|
||||
expect_sv<simde__m128i, 2>([](auto a, auto k) { return dpf::lane_arith::mul_epi2(a, k); });
|
||||
expect_sv<simde__m256i, 2>([](auto a, auto k) { return dpf::lane_arith::mul_epi2(a, k); });
|
||||
|
||||
expect_vv<simde__m128i, 4>([](auto a, auto b) { return dpf::lane_arith::add_epi4(a, b); }, add4);
|
||||
expect_vv<simde__m256i, 4>([](auto a, auto b) { return dpf::lane_arith::add_epi4(a, b); }, add4);
|
||||
expect_vv<simde__m128i, 4>([](auto a, auto b) { return dpf::lane_arith::sub_epi4(a, b); }, sub4);
|
||||
expect_vv<simde__m256i, 4>([](auto a, auto b) { return dpf::lane_arith::sub_epi4(a, b); }, sub4);
|
||||
expect_vv<simde__m128i, 4>([](auto a, auto b) { return dpf::lane_arith::mullo_epi4(a, b); }, mul4);
|
||||
expect_vv<simde__m256i, 4>([](auto a, auto b) { return dpf::lane_arith::mullo_epi4(a, b); }, mul4);
|
||||
expect_sv<simde__m128i, 4>([](auto a, auto k) { return dpf::lane_arith::mul_epi4(a, k); });
|
||||
expect_sv<simde__m256i, 4>([](auto a, auto k) { return dpf::lane_arith::mul_epi4(a, k); });
|
||||
}
|
||||
|
||||
TEST(PackedLane, LeafFunctorsMatchSimd)
|
||||
{
|
||||
alignas(32) unsigned char bytes[32];
|
||||
for (int i = 0; i < 32; ++i)
|
||||
bytes[i] = static_cast<unsigned char>(0x5a ^ i);
|
||||
simde__m128i a128, b128;
|
||||
simde__m256i a256, b256;
|
||||
std::memcpy(&a128, bytes, 16);
|
||||
std::memcpy(&b128, bytes + 8, 16);
|
||||
std::memcpy(&a256, bytes, 32);
|
||||
std::memcpy(&b256, bytes, 32);
|
||||
|
||||
auto sum128 = dpf::add_leaf<dpf::twobit>(a128, b128);
|
||||
auto via = dpf::lane_arith::add_epi2(a128, b128);
|
||||
EXPECT_EQ(std::memcmp(&sum128, &via, sizeof(via)), 0);
|
||||
|
||||
auto scaled = dpf::multiply_leaf(a256, dpf::nyble{7});
|
||||
auto via4 = dpf::lane_arith::mul_epi4(a256, dpf::nyble{7});
|
||||
EXPECT_EQ(std::memcmp(&scaled, &via4, sizeof(via4)), 0);
|
||||
|
||||
std::array<simde__m128i, 2> aa{a128, b128};
|
||||
std::array<simde__m128i, 2> bb{b128, a128};
|
||||
auto both = dpf::add_leaf<dpf::nyble>(aa, bb);
|
||||
auto e0 = dpf::lane_arith::add_epi4(a128, b128);
|
||||
auto e1 = dpf::lane_arith::add_epi4(b128, a128);
|
||||
EXPECT_EQ(std::memcmp(&both[0], &e0, sizeof(e0)), 0);
|
||||
EXPECT_EQ(std::memcmp(&both[1], &e1, sizeof(e1)), 0);
|
||||
}
|
||||
|
||||
TEST(PackedLane, DepositExtractAndBuffer)
|
||||
{
|
||||
for (std::size_t lane : {0u, 1u, 63u, 64u, 127u})
|
||||
{
|
||||
check_deposit<simde__m128i, dpf::bit>(lane);
|
||||
check_deposit<simde__m128i, dpf::twobit>(lane < 64 ? lane : lane / 2);
|
||||
check_deposit<simde__m128i, dpf::nyble>(lane % 32);
|
||||
}
|
||||
for (std::size_t lane : {0u, 127u, 128u, 200u, 255u})
|
||||
{
|
||||
check_deposit<simde__m256i, dpf::bit>(lane);
|
||||
check_deposit<simde__m256i, dpf::twobit>(lane < 128 ? lane : 127);
|
||||
check_deposit<simde__m256i, dpf::nyble>(lane % 64);
|
||||
}
|
||||
|
||||
simde__m128i leaf{};
|
||||
for (std::size_t i = 0; i < 64; ++i)
|
||||
dpf::packed::deposit_lane(leaf, i, dpf::to_twobit(static_cast<unsigned>(i)));
|
||||
dpf::output_buffer<dpf::twobit> buf(128);
|
||||
dpf::store_leaf_bytes(buf, 0, leaf);
|
||||
simde__m128i other{};
|
||||
dpf::packed::deposit_lane(other, 3, dpf::twobit::two);
|
||||
dpf::store_leaf_bytes(buf, 1, other);
|
||||
for (std::size_t i = 0; i < 64; ++i)
|
||||
{
|
||||
EXPECT_EQ(static_cast<dpf::twobit>(buf[i]),
|
||||
dpf::to_twobit(static_cast<unsigned>(i)));
|
||||
}
|
||||
EXPECT_EQ(static_cast<dpf::twobit>(buf[64 + 3]), dpf::twobit::two);
|
||||
EXPECT_EQ(static_cast<dpf::twobit>(buf[64]), dpf::twobit::zero);
|
||||
|
||||
buf[5] = dpf::twobit::one;
|
||||
EXPECT_EQ(static_cast<dpf::twobit>(buf[5]), dpf::twobit::one);
|
||||
}
|
||||
|
||||
TEST(PackedLane, DpfPointAndInterval)
|
||||
{
|
||||
check_dpf_output(dpf::twobit::three);
|
||||
check_dpf_output(dpf::nyble{0x0d});
|
||||
check_dpf_output(dpf::twobit::zero);
|
||||
check_dpf_output(dpf::nyble{1});
|
||||
}
|
||||
225
test/tests/parallel_bit_iterable_test.cpp
Normal file
225
test/tests/parallel_bit_iterable_test.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
TEST(ParallelBitIterableTest, BasicUsageBatchSize02)
|
||||
{
|
||||
constexpr std::size_t test_size = 2;
|
||||
using input_type = uint16_t;
|
||||
using output_type = dpf::bit;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
using element_type = typename dpf::parallel_const_bit_iterator<test_size, dpf::dynamic_bit_array<>>::value_type::value_type;
|
||||
const std::size_t bitlength_of_element = dpf::utils::bitlength_of_v<element_type>;
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
output_type y = dpf::bit::one;
|
||||
constexpr std::array<input_type, test_size> x{0x5555, 0xAAAA};
|
||||
auto [dpf00, dpf01] = dpf::make_dpf(x[0], y);
|
||||
auto [dpf10, dpf11] = dpf::make_dpf(x[1], y);
|
||||
auto [buf00, iter00] = dpf::eval_full(dpf00, memo0);
|
||||
auto [buf01, iter01] = dpf::eval_full(dpf01, memo1);
|
||||
auto [buf10, iter10] = dpf::eval_full(dpf10, memo0);
|
||||
auto [buf11, iter11] = dpf::eval_full(dpf11, memo1);
|
||||
|
||||
auto parallel0 = dpf::batch_of(buf00, buf10),
|
||||
parallel1 = dpf::batch_of(buf01, buf11);
|
||||
|
||||
auto it0 = std::begin(parallel0), it1 = std::begin(parallel1);
|
||||
for (std::size_t i = 0, idx = 0; i < std::size_t(1)<<dpf::utils::bitlength_of_v<input_type>; ++i, ++it0, ++it1)
|
||||
{
|
||||
auto tmp = *it0;
|
||||
if (idx < test_size && i == x[idx])
|
||||
{
|
||||
tmp[idx] ^= element_type(1) << x[idx]%bitlength_of_element;
|
||||
++idx;
|
||||
}
|
||||
ASSERT_EQ(tmp, *it1);
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(parallel0));
|
||||
ASSERT_EQ(it1, std::end(parallel1));
|
||||
}
|
||||
|
||||
TEST(ParallelBitIterableTest, BasicUsageBatchSize04)
|
||||
{
|
||||
constexpr std::size_t test_size = 4;
|
||||
using input_type = uint16_t;
|
||||
using output_type = dpf::bit;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
using element_type = typename dpf::parallel_const_bit_iterator<test_size, dpf::dynamic_bit_array<>>::value_type::value_type;
|
||||
const std::size_t bitlength_of_element = dpf::utils::bitlength_of_v<element_type>;
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
output_type y = dpf::bit::one;
|
||||
constexpr std::array<input_type, test_size> x{0x0000, 0x5555, 0xAAAA, 0xFFFF};
|
||||
auto [dpf00, dpf01] = dpf::make_dpf(x[0], y);
|
||||
auto [dpf10, dpf11] = dpf::make_dpf(x[1], y);
|
||||
auto [dpf20, dpf21] = dpf::make_dpf(x[2], y);
|
||||
auto [dpf30, dpf31] = dpf::make_dpf(x[3], y);
|
||||
auto [buf00, iter00] = dpf::eval_full(dpf00, memo0);
|
||||
auto [buf01, iter01] = dpf::eval_full(dpf01, memo1);
|
||||
auto [buf10, iter10] = dpf::eval_full(dpf10, memo0);
|
||||
auto [buf11, iter11] = dpf::eval_full(dpf11, memo1);
|
||||
auto [buf20, iter20] = dpf::eval_full(dpf20, memo0);
|
||||
auto [buf21, iter21] = dpf::eval_full(dpf21, memo1);
|
||||
auto [buf30, iter30] = dpf::eval_full(dpf30, memo0);
|
||||
auto [buf31, iter31] = dpf::eval_full(dpf31, memo1);
|
||||
|
||||
auto parallel0 = dpf::batch_of(buf00, buf10, buf20, buf30),
|
||||
parallel1 = dpf::batch_of(buf01, buf11, buf21, buf31);
|
||||
|
||||
auto it0 = std::begin(parallel0), it1 = std::begin(parallel1);
|
||||
for (std::size_t i = 0, idx = 0; i < std::size_t(1)<<dpf::utils::bitlength_of_v<input_type>; ++i, ++it0, ++it1)
|
||||
{
|
||||
auto tmp = *it0;
|
||||
if (idx < test_size && i == x[idx])
|
||||
{
|
||||
tmp[idx] ^= element_type(1) << x[idx]%bitlength_of_element;
|
||||
++idx;
|
||||
}
|
||||
ASSERT_EQ(tmp, *it1);
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(parallel0));
|
||||
ASSERT_EQ(it1, std::end(parallel1));
|
||||
}
|
||||
|
||||
TEST(ParallelBitIterableTest, BasicUsageBatchSize08)
|
||||
{
|
||||
constexpr std::size_t test_size = 8;
|
||||
using input_type = uint16_t;
|
||||
using output_type = dpf::bit;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
using element_type = typename dpf::parallel_const_bit_iterator<test_size, dpf::dynamic_bit_array<>>::value_type::value_type;
|
||||
const std::size_t bitlength_of_element = dpf::utils::bitlength_of_v<element_type>;
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
output_type y = dpf::bit::one;
|
||||
constexpr std::array<input_type, test_size> x{0x0000, 0x3333, 0x5555, 0x7FFF,
|
||||
0x8000, 0xAAAA, 0xCCCC, 0xFFFF};
|
||||
auto [dpf00, dpf01] = dpf::make_dpf(x[0], y);
|
||||
auto [dpf10, dpf11] = dpf::make_dpf(x[1], y);
|
||||
auto [dpf20, dpf21] = dpf::make_dpf(x[2], y);
|
||||
auto [dpf30, dpf31] = dpf::make_dpf(x[3], y);
|
||||
auto [dpf40, dpf41] = dpf::make_dpf(x[4], y);
|
||||
auto [dpf50, dpf51] = dpf::make_dpf(x[5], y);
|
||||
auto [dpf60, dpf61] = dpf::make_dpf(x[6], y);
|
||||
auto [dpf70, dpf71] = dpf::make_dpf(x[7], y);
|
||||
auto [buf00, iter00] = dpf::eval_full(dpf00, memo0);
|
||||
auto [buf01, iter01] = dpf::eval_full(dpf01, memo1);
|
||||
auto [buf10, iter10] = dpf::eval_full(dpf10, memo0);
|
||||
auto [buf11, iter11] = dpf::eval_full(dpf11, memo1);
|
||||
auto [buf20, iter20] = dpf::eval_full(dpf20, memo0);
|
||||
auto [buf21, iter21] = dpf::eval_full(dpf21, memo1);
|
||||
auto [buf30, iter30] = dpf::eval_full(dpf30, memo0);
|
||||
auto [buf31, iter31] = dpf::eval_full(dpf31, memo1);
|
||||
auto [buf40, iter40] = dpf::eval_full(dpf40, memo0);
|
||||
auto [buf41, iter41] = dpf::eval_full(dpf41, memo1);
|
||||
auto [buf50, iter50] = dpf::eval_full(dpf50, memo0);
|
||||
auto [buf51, iter51] = dpf::eval_full(dpf51, memo1);
|
||||
auto [buf60, iter60] = dpf::eval_full(dpf60, memo0);
|
||||
auto [buf61, iter61] = dpf::eval_full(dpf61, memo1);
|
||||
auto [buf70, iter70] = dpf::eval_full(dpf70, memo0);
|
||||
auto [buf71, iter71] = dpf::eval_full(dpf71, memo1);
|
||||
|
||||
auto parallel0 = dpf::batch_of(buf00, buf10, buf20, buf30, buf40, buf50, buf60, buf70),
|
||||
parallel1 = dpf::batch_of(buf01, buf11, buf21, buf31, buf41, buf51, buf61, buf71);
|
||||
|
||||
auto it0 = std::begin(parallel0), it1 = std::begin(parallel1);
|
||||
for (std::size_t i = 0, idx = 0; i < std::size_t(1)<<dpf::utils::bitlength_of_v<input_type>; ++i, ++it0, ++it1)
|
||||
{
|
||||
auto tmp = *it0;
|
||||
if (idx < test_size && i == x[idx])
|
||||
{
|
||||
tmp[idx] ^= element_type(1) << x[idx]%bitlength_of_element;
|
||||
++idx;
|
||||
}
|
||||
ASSERT_EQ(tmp, *it1);
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(parallel0));
|
||||
ASSERT_EQ(it1, std::end(parallel1));
|
||||
}
|
||||
|
||||
TEST(ParallelBitIterableTest, BasicUsageBatchSize16)
|
||||
{
|
||||
constexpr std::size_t test_size = 16;
|
||||
using input_type = uint16_t;
|
||||
using output_type = dpf::bit;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
using element_type = typename dpf::parallel_const_bit_iterator<test_size, dpf::dynamic_bit_array<>>::value_type::value_type;
|
||||
const std::size_t bitlength_of_element = dpf::utils::bitlength_of_v<element_type>;
|
||||
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>(),
|
||||
memo1 = dpf::make_basic_full_memoizer<dpf_type>();
|
||||
output_type y = dpf::bit::one;
|
||||
constexpr std::array<input_type, test_size> x{0x0000, 0x1111, 0x2222, 0x3333,
|
||||
0x4444, 0x5555, 0x6666, 0x7FFF,
|
||||
0x8000, 0x9999, 0xAAAA, 0xBBBB,
|
||||
0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF};
|
||||
auto [dpf000, dpf001] = dpf::make_dpf(x[ 0], y);
|
||||
auto [dpf010, dpf011] = dpf::make_dpf(x[ 1], y);
|
||||
auto [dpf020, dpf021] = dpf::make_dpf(x[ 2], y);
|
||||
auto [dpf030, dpf031] = dpf::make_dpf(x[ 3], y);
|
||||
auto [dpf040, dpf041] = dpf::make_dpf(x[ 4], y);
|
||||
auto [dpf050, dpf051] = dpf::make_dpf(x[ 5], y);
|
||||
auto [dpf060, dpf061] = dpf::make_dpf(x[ 6], y);
|
||||
auto [dpf070, dpf071] = dpf::make_dpf(x[ 7], y);
|
||||
auto [dpf080, dpf081] = dpf::make_dpf(x[ 8], y);
|
||||
auto [dpf090, dpf091] = dpf::make_dpf(x[ 9], y);
|
||||
auto [dpf100, dpf101] = dpf::make_dpf(x[10], y);
|
||||
auto [dpf110, dpf111] = dpf::make_dpf(x[11], y);
|
||||
auto [dpf120, dpf121] = dpf::make_dpf(x[12], y);
|
||||
auto [dpf130, dpf131] = dpf::make_dpf(x[13], y);
|
||||
auto [dpf140, dpf141] = dpf::make_dpf(x[14], y);
|
||||
auto [dpf150, dpf151] = dpf::make_dpf(x[15], y);
|
||||
auto [buf000, iter000] = dpf::eval_full(dpf000, memo0);
|
||||
auto [buf001, iter001] = dpf::eval_full(dpf001, memo1);
|
||||
auto [buf010, iter010] = dpf::eval_full(dpf010, memo0);
|
||||
auto [buf011, iter011] = dpf::eval_full(dpf011, memo1);
|
||||
auto [buf020, iter020] = dpf::eval_full(dpf020, memo0);
|
||||
auto [buf021, iter021] = dpf::eval_full(dpf021, memo1);
|
||||
auto [buf030, iter030] = dpf::eval_full(dpf030, memo0);
|
||||
auto [buf031, iter031] = dpf::eval_full(dpf031, memo1);
|
||||
auto [buf040, iter040] = dpf::eval_full(dpf040, memo0);
|
||||
auto [buf041, iter041] = dpf::eval_full(dpf041, memo1);
|
||||
auto [buf050, iter050] = dpf::eval_full(dpf050, memo0);
|
||||
auto [buf051, iter051] = dpf::eval_full(dpf051, memo1);
|
||||
auto [buf060, iter060] = dpf::eval_full(dpf060, memo0);
|
||||
auto [buf061, iter061] = dpf::eval_full(dpf061, memo1);
|
||||
auto [buf070, iter070] = dpf::eval_full(dpf070, memo0);
|
||||
auto [buf071, iter071] = dpf::eval_full(dpf071, memo1);
|
||||
auto [buf080, iter080] = dpf::eval_full(dpf080, memo0);
|
||||
auto [buf081, iter081] = dpf::eval_full(dpf081, memo1);
|
||||
auto [buf090, iter090] = dpf::eval_full(dpf090, memo0);
|
||||
auto [buf091, iter091] = dpf::eval_full(dpf091, memo1);
|
||||
auto [buf100, iter100] = dpf::eval_full(dpf100, memo0);
|
||||
auto [buf101, iter101] = dpf::eval_full(dpf101, memo1);
|
||||
auto [buf110, iter110] = dpf::eval_full(dpf110, memo0);
|
||||
auto [buf111, iter111] = dpf::eval_full(dpf111, memo1);
|
||||
auto [buf120, iter120] = dpf::eval_full(dpf120, memo0);
|
||||
auto [buf121, iter121] = dpf::eval_full(dpf121, memo1);
|
||||
auto [buf130, iter130] = dpf::eval_full(dpf130, memo0);
|
||||
auto [buf131, iter131] = dpf::eval_full(dpf131, memo1);
|
||||
auto [buf140, iter140] = dpf::eval_full(dpf140, memo0);
|
||||
auto [buf141, iter141] = dpf::eval_full(dpf141, memo1);
|
||||
auto [buf150, iter150] = dpf::eval_full(dpf150, memo0);
|
||||
auto [buf151, iter151] = dpf::eval_full(dpf151, memo1);
|
||||
|
||||
auto parallel0 = dpf::batch_of(buf000, buf010, buf020, buf030, buf040, buf050, buf060, buf070,
|
||||
buf080, buf090, buf100, buf110, buf120, buf130, buf140, buf150),
|
||||
parallel1 = dpf::batch_of(buf001, buf011, buf021, buf031, buf041, buf051, buf061, buf071,
|
||||
buf081, buf091, buf101, buf111, buf121, buf131, buf141, buf151);
|
||||
|
||||
auto it0 = std::begin(parallel0), it1 = std::begin(parallel1);
|
||||
for (std::size_t i = 0, idx = 0; i < std::size_t(1)<<dpf::utils::bitlength_of_v<input_type>; ++i, ++it0, ++it1)
|
||||
{
|
||||
auto tmp = *it0;
|
||||
if (idx < test_size && i == x[idx])
|
||||
{
|
||||
tmp[idx] ^= element_type(1) << x[idx]%bitlength_of_element;
|
||||
++idx;
|
||||
}
|
||||
ASSERT_EQ(tmp, *it1);
|
||||
}
|
||||
ASSERT_EQ(it0, std::end(parallel0));
|
||||
ASSERT_EQ(it1, std::end(parallel1));
|
||||
}
|
||||
129
test/tests/prg_lowmc_test.cpp
Normal file
129
test/tests/prg_lowmc_test.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "simde/simde/x86/avx2.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool blocks_equal(simde__m128i a, simde__m128i b)
|
||||
{
|
||||
return simde_mm_movemask_epi8(simde_mm_cmpeq_epi8(a, b)) == 0xFFFF;
|
||||
}
|
||||
|
||||
simde__m128i block_from_lanes(std::uint64_t lo, std::uint64_t hi)
|
||||
{
|
||||
simde__m128i x;
|
||||
std::uint64_t lane[2] = {lo, hi};
|
||||
std::memcpy(&x, lane, sizeof(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(LowmcPrg, EncryptDecryptRoundtrip)
|
||||
{
|
||||
lowmc::LowMC cipher;
|
||||
lowmc::block plain = 0;
|
||||
plain[0] = 1;
|
||||
plain[127] = 1;
|
||||
plain[64] = 1;
|
||||
lowmc::block ciphered = cipher.encrypt(plain);
|
||||
EXPECT_TRUE(cipher.decrypt(ciphered) == plain);
|
||||
EXPECT_TRUE(ciphered != plain);
|
||||
}
|
||||
|
||||
TEST(LowmcPrg, EvalAgreesWithBulk)
|
||||
{
|
||||
using prg = dpf::prg::lowmc128;
|
||||
simde__m128i seed = block_from_lanes(0x0123456789abcdefull, 0xfedcba9876543210ull);
|
||||
|
||||
auto kids = prg::eval01(seed);
|
||||
EXPECT_TRUE(blocks_equal(kids[0], prg::eval(seed, 0)));
|
||||
EXPECT_TRUE(blocks_equal(kids[1], prg::eval(seed, 1)));
|
||||
EXPECT_FALSE(blocks_equal(kids[0], kids[1]));
|
||||
EXPECT_FALSE(blocks_equal(kids[0], seed));
|
||||
|
||||
alignas(16) simde__m128i bulk[4];
|
||||
prg::eval(seed, bulk, 4, 0);
|
||||
EXPECT_TRUE(blocks_equal(bulk[0], kids[0]));
|
||||
EXPECT_TRUE(blocks_equal(bulk[1], kids[1]));
|
||||
EXPECT_TRUE(blocks_equal(bulk[2], prg::eval(seed, 2)));
|
||||
EXPECT_TRUE(blocks_equal(bulk[3], prg::eval(seed, 3)));
|
||||
|
||||
alignas(16) simde__m128i seeds[8];
|
||||
alignas(16) simde__m128i out4[4];
|
||||
alignas(16) simde__m128i out8[8];
|
||||
alignas(16) simde__m128i left[4];
|
||||
alignas(16) simde__m128i right[4];
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
seeds[i] = block_from_lanes(0x1000u + static_cast<unsigned>(i), 0x2000u);
|
||||
}
|
||||
prg::eval_x4(seeds, out4, 3);
|
||||
prg::eval_x8(seeds, out8, 5);
|
||||
prg::eval01_x4(seeds, left, right);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_TRUE(blocks_equal(out4[i], prg::eval(seeds[i], 3)));
|
||||
EXPECT_TRUE(blocks_equal(left[i], prg::eval(seeds[i], 0)));
|
||||
EXPECT_TRUE(blocks_equal(right[i], prg::eval(seeds[i], 1)));
|
||||
}
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
EXPECT_TRUE(blocks_equal(out8[i], prg::eval(seeds[i], 5)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LowmcPrg, DpfPoint)
|
||||
{
|
||||
using prg = dpf::prg::lowmc128;
|
||||
const std::uint8_t x = 0x2a;
|
||||
const std::uint32_t y = 0x01020304;
|
||||
auto [k0, k1] = dpf::make_dpf<prg>(x, y);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
auto y0 = *dpf::eval_point(k0, static_cast<std::uint8_t>(i));
|
||||
auto y1 = *dpf::eval_point(k1, static_cast<std::uint8_t>(i));
|
||||
auto sum = dpf::reconstruct(y0, y1);
|
||||
if (static_cast<std::uint8_t>(i) == x)
|
||||
{
|
||||
EXPECT_EQ(sum, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EQ(sum, 0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LowmcPrg, CounterWrapperCountsEval01)
|
||||
{
|
||||
using prg = dpf::prg::counter_wrapper<dpf::prg::lowmc128>;
|
||||
const auto before = prg::count();
|
||||
simde__m128i seed = block_from_lanes(0x1111ull, 0x2222ull);
|
||||
auto kids = prg::eval01(seed);
|
||||
EXPECT_FALSE(blocks_equal(kids[0], kids[1]));
|
||||
EXPECT_EQ(prg::count(), before + 2u);
|
||||
|
||||
alignas(16) simde__m128i bulk[4];
|
||||
prg::eval(seed, bulk, 4, 0);
|
||||
EXPECT_EQ(prg::count(), before + 2u + 4u);
|
||||
}
|
||||
|
||||
TEST(LowmcPrg, CounterWrapperDpfGenAndPoint)
|
||||
{
|
||||
using prg = dpf::prg::counter_wrapper<dpf::prg::lowmc128>;
|
||||
const auto before = prg::count();
|
||||
const std::uint8_t x = 0x91;
|
||||
const std::uint32_t y = 0xdeadbeef;
|
||||
auto [k0, k1] = dpf::make_dpf<prg>(x, y);
|
||||
EXPECT_GT(prg::count(), before);
|
||||
auto y0 = *dpf::eval_point(k0, x);
|
||||
auto y1 = *dpf::eval_point(k1, x);
|
||||
EXPECT_EQ(dpf::reconstruct(y0, y1), y);
|
||||
}
|
||||
171
test/tests/principal_lut_test.cpp
Normal file
171
test/tests/principal_lut_test.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "grotto/principal_lut.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct sample
|
||||
{
|
||||
int which;
|
||||
unsigned k;
|
||||
std::int64_t raw;
|
||||
std::int64_t y;
|
||||
};
|
||||
|
||||
const sample kSamples[] = {
|
||||
#include "principal_samples.inc"
|
||||
};
|
||||
|
||||
long double series_coth_minus_inv(long double u)
|
||||
{
|
||||
const long double u2 = u * u;
|
||||
return u * (1.0L / 3.0L - u2 / 45.0L + 2.0L * u2 * u2 / 945.0L);
|
||||
}
|
||||
|
||||
long double reference(grotto::principal which, unsigned k, long double x)
|
||||
{
|
||||
constexpr long double pi = 3.141592653589793238462643383279502884L;
|
||||
switch (which)
|
||||
{
|
||||
case grotto::principal::ln:
|
||||
return logl(x);
|
||||
case grotto::principal::exp:
|
||||
return expl(ldexpl(x, -13));
|
||||
case grotto::principal::sin:
|
||||
return sinl(pi * x / 2);
|
||||
case grotto::principal::tanf:
|
||||
if (x == 0)
|
||||
return 1;
|
||||
{
|
||||
const long double z = pi * x / 4;
|
||||
return tanl(z) / z;
|
||||
}
|
||||
case grotto::principal::tang:
|
||||
if (x < ldexpl(1, -12))
|
||||
{
|
||||
const long double z = pi * x / 4;
|
||||
const long double z2 = z * z;
|
||||
return -z / 3 - z2 * z / 45;
|
||||
}
|
||||
{
|
||||
const long double z = pi * x / 4;
|
||||
return 1 / tanl(z) - 1 / z;
|
||||
}
|
||||
case grotto::principal::sinh:
|
||||
return sinhl(ldexpl(x, -13));
|
||||
case grotto::principal::cosh:
|
||||
return coshl(ldexpl(x, -13));
|
||||
case grotto::principal::sqrt:
|
||||
return sqrtl(x);
|
||||
case grotto::principal::coth:
|
||||
if (x == 0)
|
||||
return 0;
|
||||
{
|
||||
const long double beta = 0.5L * logl(ldexpl(1, static_cast<int>(k) + 1) + 1);
|
||||
const long double u = beta * x;
|
||||
if (u < 0.05L)
|
||||
return series_coth_minus_inv(u);
|
||||
return 1 / tanhl(u) - 1 / u;
|
||||
}
|
||||
case grotto::principal::sec:
|
||||
return 1 / cosl(pi * x / 4);
|
||||
case grotto::principal::gsec:
|
||||
if (x < ldexpl(1, -12))
|
||||
{
|
||||
const long double z = pi * x / 4;
|
||||
const long double z2 = z * z;
|
||||
return z / 6 + 7 * z2 * z / 360;
|
||||
}
|
||||
{
|
||||
const long double z = pi * x / 4;
|
||||
return 1 / sinl(z) - 1 / z;
|
||||
}
|
||||
case grotto::principal::csch:
|
||||
if (x < ldexpl(1, -12))
|
||||
{
|
||||
const long double x2 = x * x;
|
||||
return -x / 6 + 7 * x2 * x / 360;
|
||||
}
|
||||
return 1 / sinhl(x) - 1 / x;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::int64_t domain_left(grotto::principal which, unsigned k)
|
||||
{
|
||||
if (which == grotto::principal::ln || which == grotto::principal::sqrt)
|
||||
return std::int64_t{1} << (k - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::int64_t domain_right(unsigned k)
|
||||
{
|
||||
return std::int64_t{1} << k;
|
||||
}
|
||||
|
||||
void expect_close(grotto::principal which, unsigned k, std::int64_t raw)
|
||||
{
|
||||
const auto y = grotto::eval_principal(which, k, raw);
|
||||
const long double x = ldexpl(static_cast<long double>(raw), -static_cast<int>(k));
|
||||
const long double truth = reference(which, k, x) * ldexpl(1, static_cast<int>(k));
|
||||
EXPECT_LE(fabsl(static_cast<long double>(y) - truth), 1.5L) << static_cast<int>(which) << " k=" << k << " raw=" << raw;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(PrincipalLut, CoarsenedPieceCountsStayPut)
|
||||
{
|
||||
EXPECT_EQ(grotto::principal_parts(grotto::principal::ln, 8), grotto::principal_parts(grotto::principal::ln, 32));
|
||||
EXPECT_EQ(grotto::principal_parts(grotto::principal::sqrt, 8), 393);
|
||||
EXPECT_EQ(grotto::principal_parts(grotto::principal::exp, 32), 2u);
|
||||
EXPECT_EQ(grotto::principal_parts(grotto::principal::sinh, 16), 1u);
|
||||
EXPECT_LT(grotto::principal_parts(grotto::principal::coth, 8), grotto::principal_parts(grotto::principal::coth, 32));
|
||||
}
|
||||
|
||||
TEST(PrincipalLut, EmbeddedHornerMatches)
|
||||
{
|
||||
for (const sample & point : kSamples)
|
||||
{
|
||||
const auto which = static_cast<grotto::principal>(point.which);
|
||||
EXPECT_EQ(grotto::eval_principal(which, point.k, point.raw), point.y)
|
||||
<< point.which << " k=" << point.k << " raw=" << point.raw;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PrincipalLut, WithinOneUlpOnTheDomain)
|
||||
{
|
||||
for (unsigned which_i = 0; which_i < 12; ++which_i)
|
||||
{
|
||||
const auto which = static_cast<grotto::principal>(which_i);
|
||||
for (unsigned k : {8u, 12u})
|
||||
{
|
||||
const auto left = domain_left(which, k);
|
||||
const auto right = domain_right(k);
|
||||
for (std::int64_t raw = left; raw <= right; ++raw)
|
||||
expect_close(which, k, raw);
|
||||
}
|
||||
for (unsigned k : {16u, 20u, 24u, 28u, 32u})
|
||||
{
|
||||
const auto left = domain_left(which, k);
|
||||
const auto right = domain_right(k);
|
||||
const std::int64_t step = std::max<std::int64_t>(1, (right - left) / 256);
|
||||
expect_close(which, k, left);
|
||||
expect_close(which, k, right);
|
||||
for (std::int64_t raw = left; raw < right; raw += step)
|
||||
expect_close(which, k, raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PrincipalLut, RejectsBadPrecisionAndDomain)
|
||||
{
|
||||
EXPECT_THROW(grotto::eval_principal(grotto::principal::ln, 7, 64), std::invalid_argument);
|
||||
EXPECT_THROW(grotto::eval_principal(grotto::principal::ln, 8, 0), std::out_of_range);
|
||||
EXPECT_THROW(grotto::eval_principal(grotto::principal::exp, 8, -1), std::out_of_range);
|
||||
EXPECT_THROW(grotto::eval_principal(grotto::principal::sin, 8, 257), std::out_of_range);
|
||||
}
|
||||
934
test/tests/principal_samples.inc
Normal file
934
test/tests/principal_samples.inc
Normal file
|
|
@ -0,0 +1,934 @@
|
|||
{0, 8, 128, -177},
|
||||
{0, 8, 192, -74},
|
||||
{0, 8, 256, 0},
|
||||
{0, 12, 2048, -2839},
|
||||
{0, 12, 3072, -1178},
|
||||
{0, 12, 4096, 0},
|
||||
{0, 16, 32768, -45426},
|
||||
{0, 16, 33026, -44912},
|
||||
{0, 16, 33546, -43888},
|
||||
{0, 16, 34074, -42865},
|
||||
{0, 16, 34611, -41840},
|
||||
{0, 16, 35156, -40816},
|
||||
{0, 16, 35710, -39791},
|
||||
{0, 16, 36272, -38768},
|
||||
{0, 16, 36843, -37744},
|
||||
{0, 16, 37423, -36721},
|
||||
{0, 16, 38013, -35696},
|
||||
{0, 16, 38611, -34673},
|
||||
{0, 16, 39219, -33649},
|
||||
{0, 16, 39837, -32624},
|
||||
{0, 16, 40464, -31601},
|
||||
{0, 16, 41101, -30577},
|
||||
{0, 16, 41749, -29552},
|
||||
{0, 16, 42406, -28528},
|
||||
{0, 16, 43074, -27504},
|
||||
{0, 16, 43752, -26481},
|
||||
{0, 16, 44441, -25457},
|
||||
{0, 16, 45141, -24432},
|
||||
{0, 16, 45852, -23408},
|
||||
{0, 16, 46574, -22384},
|
||||
{0, 16, 47307, -21361},
|
||||
{0, 16, 48052, -20337},
|
||||
{0, 16, 48809, -19312},
|
||||
{0, 16, 49152, -18854},
|
||||
{0, 16, 49578, -18288},
|
||||
{0, 16, 50358, -17265},
|
||||
{0, 16, 51151, -16241},
|
||||
{0, 16, 51957, -15216},
|
||||
{0, 16, 52775, -14193},
|
||||
{0, 16, 53605, -13170},
|
||||
{0, 16, 54449, -12146},
|
||||
{0, 16, 55306, -11123},
|
||||
{0, 16, 56177, -10099},
|
||||
{0, 16, 57062, -9074},
|
||||
{0, 16, 57960, -8051},
|
||||
{0, 16, 58873, -7027},
|
||||
{0, 16, 59800, -6003},
|
||||
{0, 16, 60742, -4978},
|
||||
{0, 16, 61698, -3955},
|
||||
{0, 16, 62670, -2931},
|
||||
{0, 16, 63657, -1906},
|
||||
{0, 16, 64659, -883},
|
||||
{0, 16, 65350, -186},
|
||||
{0, 16, 65536, 0},
|
||||
{0, 20, 524288, -726817},
|
||||
{0, 20, 786432, -301657},
|
||||
{0, 20, 1048576, 0},
|
||||
{0, 24, 8388608, -11629080},
|
||||
{0, 24, 12582912, -4826504},
|
||||
{0, 24, 16777216, 0},
|
||||
{0, 28, 134217728, -186065279},
|
||||
{0, 28, 201326592, -77224068},
|
||||
{0, 28, 268435456, 0},
|
||||
{0, 32, 2147483648, -2977044471},
|
||||
{0, 32, 3221225472, -1235585093},
|
||||
{0, 32, 4294967296, 0},
|
||||
{1, 8, 0, 256},
|
||||
{1, 8, 128, 256},
|
||||
{1, 8, 256, 256},
|
||||
{1, 12, 0, 4096},
|
||||
{1, 12, 2048, 4096},
|
||||
{1, 12, 4096, 4097},
|
||||
{1, 16, 0, 65536},
|
||||
{1, 16, 30489, 65540},
|
||||
{1, 16, 32768, 65540},
|
||||
{1, 16, 63257, 65544},
|
||||
{1, 16, 65536, 65544},
|
||||
{1, 20, 0, 1048576},
|
||||
{1, 20, 524288, 1048640},
|
||||
{1, 20, 1048576, 1048704},
|
||||
{1, 24, 0, 16777216},
|
||||
{1, 24, 8388608, 16778240},
|
||||
{1, 24, 16777216, 16779264},
|
||||
{1, 28, 0, 268435456},
|
||||
{1, 28, 134217728, 268451841},
|
||||
{1, 28, 268435456, 268468226},
|
||||
{1, 32, 0, 4294967296},
|
||||
{1, 32, 2147483648, 4295229448},
|
||||
{1, 32, 4294967296, 4295491616},
|
||||
{2, 8, 0, 0},
|
||||
{2, 8, 128, 181},
|
||||
{2, 8, 256, 256},
|
||||
{2, 12, 0, 0},
|
||||
{2, 12, 2048, 2896},
|
||||
{2, 12, 4096, 4096},
|
||||
{2, 16, 0, 0},
|
||||
{2, 16, 1228, 1929},
|
||||
{2, 16, 3411, 5352},
|
||||
{2, 16, 5223, 8183},
|
||||
{2, 16, 6882, 10761},
|
||||
{2, 16, 8446, 13177},
|
||||
{2, 16, 9939, 15465},
|
||||
{2, 16, 11379, 17653},
|
||||
{2, 16, 12776, 19756},
|
||||
{2, 16, 14136, 21782},
|
||||
{2, 16, 15465, 23740},
|
||||
{2, 16, 16768, 25636},
|
||||
{2, 16, 18047, 27472},
|
||||
{2, 16, 19305, 29254},
|
||||
{2, 16, 20544, 30982},
|
||||
{2, 16, 21767, 32661},
|
||||
{2, 16, 22973, 34290},
|
||||
{2, 16, 24166, 35873},
|
||||
{2, 16, 25346, 37409},
|
||||
{2, 16, 26514, 38901},
|
||||
{2, 16, 27671, 40348},
|
||||
{2, 16, 28818, 41753},
|
||||
{2, 16, 29956, 43115},
|
||||
{2, 16, 31084, 44433},
|
||||
{2, 16, 32205, 45711},
|
||||
{2, 16, 32768, 46341},
|
||||
{2, 16, 33317, 46947},
|
||||
{2, 16, 34423, 48142},
|
||||
{2, 16, 35522, 49297},
|
||||
{2, 16, 36614, 50410},
|
||||
{2, 16, 37701, 51484},
|
||||
{2, 16, 38782, 52517},
|
||||
{2, 16, 39857, 53510},
|
||||
{2, 16, 40928, 54463},
|
||||
{2, 16, 41995, 55378},
|
||||
{2, 16, 43057, 56252},
|
||||
{2, 16, 44115, 57086},
|
||||
{2, 16, 45169, 57881},
|
||||
{2, 16, 46220, 58637},
|
||||
{2, 16, 47267, 59353},
|
||||
{2, 16, 48312, 60030},
|
||||
{2, 16, 49353, 60667},
|
||||
{2, 16, 50392, 61266},
|
||||
{2, 16, 51428, 61825},
|
||||
{2, 16, 52463, 62345},
|
||||
{2, 16, 53495, 62826},
|
||||
{2, 16, 54525, 63267},
|
||||
{2, 16, 55553, 63669},
|
||||
{2, 16, 56580, 64032},
|
||||
{2, 16, 57606, 64356},
|
||||
{2, 16, 58630, 64640},
|
||||
{2, 16, 59654, 64886},
|
||||
{2, 16, 60676, 65092},
|
||||
{2, 16, 61698, 65259},
|
||||
{2, 16, 62719, 65387},
|
||||
{2, 16, 63739, 65475},
|
||||
{2, 16, 64760, 65525},
|
||||
{2, 16, 65403, 65536},
|
||||
{2, 16, 65536, 65536},
|
||||
{2, 20, 0, 0},
|
||||
{2, 20, 524288, 741455},
|
||||
{2, 20, 1048576, 1048576},
|
||||
{2, 24, 0, 0},
|
||||
{2, 24, 8388608, 11863283},
|
||||
{2, 24, 16777216, 16777216},
|
||||
{2, 28, 0, 0},
|
||||
{2, 28, 134217728, 189812531},
|
||||
{2, 28, 268435456, 268435456},
|
||||
{2, 32, 0, 0},
|
||||
{2, 32, 2147483648, 3037000500},
|
||||
{2, 32, 4294967296, 4294967296},
|
||||
{3, 8, 0, 256},
|
||||
{3, 8, 128, 270},
|
||||
{3, 8, 256, 326},
|
||||
{3, 12, 0, 4096},
|
||||
{3, 12, 2048, 4320},
|
||||
{3, 12, 4096, 5215},
|
||||
{3, 16, 0, 65536},
|
||||
{3, 16, 810, 65538},
|
||||
{3, 16, 2430, 65555},
|
||||
{3, 16, 4046, 65587},
|
||||
{3, 16, 5658, 65637},
|
||||
{3, 16, 7264, 65702},
|
||||
{3, 16, 8862, 65784},
|
||||
{3, 16, 10450, 65881},
|
||||
{3, 16, 12028, 65994},
|
||||
{3, 16, 13592, 66122},
|
||||
{3, 16, 15144, 66265},
|
||||
{3, 16, 16680, 66423},
|
||||
{3, 16, 18201, 66596},
|
||||
{3, 16, 19706, 66782},
|
||||
{3, 16, 21193, 66983},
|
||||
{3, 16, 22663, 67196},
|
||||
{3, 16, 24114, 67423},
|
||||
{3, 16, 25546, 67663},
|
||||
{3, 16, 26960, 67916},
|
||||
{3, 16, 28354, 68181},
|
||||
{3, 16, 29728, 68457},
|
||||
{3, 16, 31083, 68746},
|
||||
{3, 16, 32419, 69045},
|
||||
{3, 16, 32768, 69126},
|
||||
{3, 16, 33734, 69356},
|
||||
{3, 16, 35031, 69678},
|
||||
{3, 16, 36307, 70011},
|
||||
{3, 16, 37565, 70354},
|
||||
{3, 16, 38803, 70708},
|
||||
{3, 16, 40022, 71071},
|
||||
{3, 16, 41223, 71445},
|
||||
{3, 16, 42405, 71829},
|
||||
{3, 16, 43568, 72221},
|
||||
{3, 16, 44713, 72624},
|
||||
{3, 16, 45841, 73036},
|
||||
{3, 16, 46950, 73456},
|
||||
{3, 16, 48043, 73887},
|
||||
{3, 16, 49118, 74326},
|
||||
{3, 16, 50176, 74773},
|
||||
{3, 16, 51218, 75230},
|
||||
{3, 16, 52243, 75695},
|
||||
{3, 16, 53253, 76169},
|
||||
{3, 16, 54246, 76651},
|
||||
{3, 16, 55224, 77142},
|
||||
{3, 16, 56187, 77641},
|
||||
{3, 16, 57134, 78148},
|
||||
{3, 16, 58067, 78664},
|
||||
{3, 16, 58986, 79188},
|
||||
{3, 16, 59890, 79719},
|
||||
{3, 16, 60780, 80259},
|
||||
{3, 16, 61657, 80807},
|
||||
{3, 16, 62520, 81363},
|
||||
{3, 16, 63369, 81927},
|
||||
{3, 16, 64206, 82499},
|
||||
{3, 16, 65030, 83079},
|
||||
{3, 16, 65487, 83407},
|
||||
{3, 16, 65536, 83443},
|
||||
{3, 20, 0, 1048576},
|
||||
{3, 20, 524288, 1106023},
|
||||
{3, 20, 1048576, 1335088},
|
||||
{3, 24, 0, 16777216},
|
||||
{3, 24, 8388608, 17696375},
|
||||
{3, 24, 16777216, 21361415},
|
||||
{3, 28, 0, 268435456},
|
||||
{3, 28, 134217728, 283142008},
|
||||
{3, 28, 268435456, 341782638},
|
||||
{3, 32, 0, 4294967295},
|
||||
{3, 32, 2147483648, 4530272127},
|
||||
{3, 32, 4294967296, 5468522205},
|
||||
{4, 8, 0, 0},
|
||||
{4, 8, 128, -34},
|
||||
{4, 8, 256, -70},
|
||||
{4, 12, 0, 0},
|
||||
{4, 12, 2048, -542},
|
||||
{4, 12, 4096, -1119},
|
||||
{4, 16, 0, 0},
|
||||
{4, 16, 3230, -846},
|
||||
{4, 16, 8964, -2349},
|
||||
{4, 16, 13714, -3597},
|
||||
{4, 16, 18051, -4741},
|
||||
{4, 16, 22119, -5818},
|
||||
{4, 16, 25989, -6848},
|
||||
{4, 16, 29700, -7842},
|
||||
{4, 16, 32768, -8668},
|
||||
{4, 16, 33279, -8806},
|
||||
{4, 16, 36743, -9746},
|
||||
{4, 16, 40106, -10665},
|
||||
{4, 16, 43377, -11566},
|
||||
{4, 16, 46565, -12452},
|
||||
{4, 16, 49677, -13323},
|
||||
{4, 16, 52717, -14183},
|
||||
{4, 16, 55689, -15031},
|
||||
{4, 16, 58598, -15870},
|
||||
{4, 16, 61447, -16700},
|
||||
{4, 16, 64196, -17509},
|
||||
{4, 16, 65536, -17907},
|
||||
{4, 20, 0, 0},
|
||||
{4, 20, 524288, -138690},
|
||||
{4, 20, 1048576, -286512},
|
||||
{4, 24, 0, 0},
|
||||
{4, 24, 8388608, -2219047},
|
||||
{4, 24, 16777216, -4584199},
|
||||
{4, 28, 0, 0},
|
||||
{4, 28, 134217728, -35504757},
|
||||
{4, 28, 268435456, -73347182},
|
||||
{4, 32, 0, 0},
|
||||
{4, 32, 2147483648, -568076113},
|
||||
{4, 32, 4294967296, -1173554908},
|
||||
{5, 8, 0, 0},
|
||||
{5, 8, 128, 0},
|
||||
{5, 8, 256, 0},
|
||||
{5, 12, 0, 0},
|
||||
{5, 12, 2048, 0},
|
||||
{5, 12, 4096, 1},
|
||||
{5, 16, 0, 0},
|
||||
{5, 16, 32768, 4},
|
||||
{5, 16, 65536, 8},
|
||||
{5, 20, 0, 0},
|
||||
{5, 20, 524288, 64},
|
||||
{5, 20, 1048576, 128},
|
||||
{5, 24, 0, 0},
|
||||
{5, 24, 8388608, 1024},
|
||||
{5, 24, 16777216, 2048},
|
||||
{5, 28, 0, 0},
|
||||
{5, 28, 134217728, 16384},
|
||||
{5, 28, 268435456, 32768},
|
||||
{5, 32, 0, 0},
|
||||
{5, 32, 2147483648, 262144},
|
||||
{5, 32, 4294967296, 524288},
|
||||
{6, 8, 0, 256},
|
||||
{6, 8, 128, 256},
|
||||
{6, 8, 256, 256},
|
||||
{6, 12, 0, 4096},
|
||||
{6, 12, 2048, 4096},
|
||||
{6, 12, 4096, 4096},
|
||||
{6, 16, 0, 65536},
|
||||
{6, 16, 30494, 65536},
|
||||
{6, 16, 32768, 65536},
|
||||
{6, 16, 63262, 65536},
|
||||
{6, 16, 65536, 65536},
|
||||
{6, 20, 0, 1048576},
|
||||
{6, 20, 524288, 1048576},
|
||||
{6, 20, 1048576, 1048576},
|
||||
{6, 24, 0, 16777216},
|
||||
{6, 24, 8388608, 16777216},
|
||||
{6, 24, 16777216, 16777216},
|
||||
{6, 28, 0, 268435456},
|
||||
{6, 28, 134217728, 268435457},
|
||||
{6, 28, 268435456, 268435458},
|
||||
{6, 32, 0, 4294967296},
|
||||
{6, 32, 2147483648, 4294967304},
|
||||
{6, 32, 4294967296, 4294967328},
|
||||
{7, 8, 128, 181},
|
||||
{7, 8, 192, 222},
|
||||
{7, 8, 256, 256},
|
||||
{7, 12, 2048, 2896},
|
||||
{7, 12, 3072, 3547},
|
||||
{7, 12, 4096, 4096},
|
||||
{7, 16, 32768, 46341},
|
||||
{7, 16, 32798, 46362},
|
||||
{7, 16, 32859, 46405},
|
||||
{7, 16, 32920, 46448},
|
||||
{7, 16, 32980, 46491},
|
||||
{7, 16, 33041, 46534},
|
||||
{7, 16, 33102, 46577},
|
||||
{7, 16, 33163, 46619},
|
||||
{7, 16, 33225, 46663},
|
||||
{7, 16, 33286, 46706},
|
||||
{7, 16, 33347, 46749},
|
||||
{7, 16, 33409, 46792},
|
||||
{7, 16, 33470, 46835},
|
||||
{7, 16, 33532, 46878},
|
||||
{7, 16, 33594, 46921},
|
||||
{7, 16, 33656, 46965},
|
||||
{7, 16, 33718, 47008},
|
||||
{7, 16, 33780, 47051},
|
||||
{7, 16, 33842, 47094},
|
||||
{7, 16, 33904, 47137},
|
||||
{7, 16, 33967, 47181},
|
||||
{7, 16, 34029, 47224},
|
||||
{7, 16, 34092, 47268},
|
||||
{7, 16, 34155, 47312},
|
||||
{7, 16, 34217, 47354},
|
||||
{7, 16, 34280, 47398},
|
||||
{7, 16, 34343, 47442},
|
||||
{7, 16, 34406, 47485},
|
||||
{7, 16, 34470, 47529},
|
||||
{7, 16, 34533, 47573},
|
||||
{7, 16, 34596, 47616},
|
||||
{7, 16, 34660, 47660},
|
||||
{7, 16, 34723, 47703},
|
||||
{7, 16, 34787, 47747},
|
||||
{7, 16, 34851, 47791},
|
||||
{7, 16, 34915, 47835},
|
||||
{7, 16, 34979, 47879},
|
||||
{7, 16, 35043, 47923},
|
||||
{7, 16, 35107, 47966},
|
||||
{7, 16, 35172, 48011},
|
||||
{7, 16, 35236, 48054},
|
||||
{7, 16, 35301, 48099},
|
||||
{7, 16, 35365, 48142},
|
||||
{7, 16, 35430, 48187},
|
||||
{7, 16, 35495, 48231},
|
||||
{7, 16, 35560, 48275},
|
||||
{7, 16, 35625, 48319},
|
||||
{7, 16, 35690, 48363},
|
||||
{7, 16, 35755, 48407},
|
||||
{7, 16, 35821, 48452},
|
||||
{7, 16, 35886, 48496},
|
||||
{7, 16, 35952, 48540},
|
||||
{7, 16, 36017, 48584},
|
||||
{7, 16, 36083, 48629},
|
||||
{7, 16, 36149, 48673},
|
||||
{7, 16, 36215, 48717},
|
||||
{7, 16, 36281, 48762},
|
||||
{7, 16, 36347, 48806},
|
||||
{7, 16, 36414, 48851},
|
||||
{7, 16, 36480, 48895},
|
||||
{7, 16, 36546, 48940},
|
||||
{7, 16, 36613, 48984},
|
||||
{7, 16, 36680, 49029},
|
||||
{7, 16, 36747, 49074},
|
||||
{7, 16, 36814, 49119},
|
||||
{7, 16, 36881, 49163},
|
||||
{7, 16, 36948, 49208},
|
||||
{7, 16, 37015, 49253},
|
||||
{7, 16, 37083, 49298},
|
||||
{7, 16, 37150, 49342},
|
||||
{7, 16, 37218, 49387},
|
||||
{7, 16, 37285, 49432},
|
||||
{7, 16, 37353, 49477},
|
||||
{7, 16, 37421, 49522},
|
||||
{7, 16, 37489, 49567},
|
||||
{7, 16, 37557, 49612},
|
||||
{7, 16, 37625, 49657},
|
||||
{7, 16, 37694, 49702},
|
||||
{7, 16, 37762, 49747},
|
||||
{7, 16, 37831, 49792},
|
||||
{7, 16, 37899, 49837},
|
||||
{7, 16, 37968, 49883},
|
||||
{7, 16, 38037, 49928},
|
||||
{7, 16, 38106, 49973},
|
||||
{7, 16, 38175, 50018},
|
||||
{7, 16, 38244, 50064},
|
||||
{7, 16, 38314, 50109},
|
||||
{7, 16, 38383, 50154},
|
||||
{7, 16, 38453, 50200},
|
||||
{7, 16, 38522, 50245},
|
||||
{7, 16, 38592, 50291},
|
||||
{7, 16, 38662, 50336},
|
||||
{7, 16, 38732, 50382},
|
||||
{7, 16, 38802, 50427},
|
||||
{7, 16, 38872, 50473},
|
||||
{7, 16, 38943, 50519},
|
||||
{7, 16, 39013, 50564},
|
||||
{7, 16, 39084, 50610},
|
||||
{7, 16, 39154, 50656},
|
||||
{7, 16, 39225, 50702},
|
||||
{7, 16, 39296, 50747},
|
||||
{7, 16, 39367, 50793},
|
||||
{7, 16, 39438, 50839},
|
||||
{7, 16, 39509, 50885},
|
||||
{7, 16, 39581, 50931},
|
||||
{7, 16, 39652, 50977},
|
||||
{7, 16, 39724, 51023},
|
||||
{7, 16, 39795, 51069},
|
||||
{7, 16, 39867, 51115},
|
||||
{7, 16, 39939, 51161},
|
||||
{7, 16, 40011, 51207},
|
||||
{7, 16, 40083, 51253},
|
||||
{7, 16, 40156, 51300},
|
||||
{7, 16, 40228, 51346},
|
||||
{7, 16, 40300, 51392},
|
||||
{7, 16, 40373, 51438},
|
||||
{7, 16, 40446, 51485},
|
||||
{7, 16, 40518, 51530},
|
||||
{7, 16, 40591, 51577},
|
||||
{7, 16, 40664, 51623},
|
||||
{7, 16, 40738, 51670},
|
||||
{7, 16, 40811, 51716},
|
||||
{7, 16, 40884, 51763},
|
||||
{7, 16, 40958, 51809},
|
||||
{7, 16, 41031, 51856},
|
||||
{7, 16, 41105, 51902},
|
||||
{7, 16, 41179, 51949},
|
||||
{7, 16, 41253, 51996},
|
||||
{7, 16, 41327, 52042},
|
||||
{7, 16, 41401, 52089},
|
||||
{7, 16, 41476, 52136},
|
||||
{7, 16, 41550, 52183},
|
||||
{7, 16, 41625, 52230},
|
||||
{7, 16, 41699, 52276},
|
||||
{7, 16, 41774, 52323},
|
||||
{7, 16, 41849, 52370},
|
||||
{7, 16, 41924, 52417},
|
||||
{7, 16, 41999, 52464},
|
||||
{7, 16, 42074, 52511},
|
||||
{7, 16, 42150, 52558},
|
||||
{7, 16, 42225, 52605},
|
||||
{7, 16, 42301, 52652},
|
||||
{7, 16, 42377, 52699},
|
||||
{7, 16, 42452, 52746},
|
||||
{7, 16, 42528, 52793},
|
||||
{7, 16, 42604, 52840},
|
||||
{7, 16, 42681, 52888},
|
||||
{7, 16, 42757, 52935},
|
||||
{7, 16, 42833, 52982},
|
||||
{7, 16, 42910, 53030},
|
||||
{7, 16, 42987, 53077},
|
||||
{7, 16, 43063, 53124},
|
||||
{7, 16, 43140, 53172},
|
||||
{7, 16, 43217, 53219},
|
||||
{7, 16, 43295, 53267},
|
||||
{7, 16, 43372, 53314},
|
||||
{7, 16, 43449, 53362},
|
||||
{7, 16, 43527, 53410},
|
||||
{7, 16, 43604, 53457},
|
||||
{7, 16, 43682, 53505},
|
||||
{7, 16, 43760, 53552},
|
||||
{7, 16, 43838, 53600},
|
||||
{7, 16, 43916, 53648},
|
||||
{7, 16, 43995, 53696},
|
||||
{7, 16, 44073, 53744},
|
||||
{7, 16, 44151, 53791},
|
||||
{7, 16, 44230, 53839},
|
||||
{7, 16, 44309, 53887},
|
||||
{7, 16, 44388, 53935},
|
||||
{7, 16, 44467, 53983},
|
||||
{7, 16, 44546, 54031},
|
||||
{7, 16, 44625, 54079},
|
||||
{7, 16, 44704, 54127},
|
||||
{7, 16, 44784, 54175},
|
||||
{7, 16, 44863, 54223},
|
||||
{7, 16, 44943, 54271},
|
||||
{7, 16, 45023, 54320},
|
||||
{7, 16, 45103, 54368},
|
||||
{7, 16, 45183, 54416},
|
||||
{7, 16, 45263, 54464},
|
||||
{7, 16, 45344, 54513},
|
||||
{7, 16, 45424, 54561},
|
||||
{7, 16, 45505, 54610},
|
||||
{7, 16, 45585, 54658},
|
||||
{7, 16, 45666, 54706},
|
||||
{7, 16, 45747, 54755},
|
||||
{7, 16, 45828, 54803},
|
||||
{7, 16, 45910, 54852},
|
||||
{7, 16, 45991, 54901},
|
||||
{7, 16, 46072, 54949},
|
||||
{7, 16, 46154, 54998},
|
||||
{7, 16, 46236, 55047},
|
||||
{7, 16, 46318, 55095},
|
||||
{7, 16, 46400, 55144},
|
||||
{7, 16, 46482, 55193},
|
||||
{7, 16, 46564, 55241},
|
||||
{7, 16, 46646, 55290},
|
||||
{7, 16, 46729, 55339},
|
||||
{7, 16, 46811, 55388},
|
||||
{7, 16, 46894, 55437},
|
||||
{7, 16, 46977, 55486},
|
||||
{7, 16, 47060, 55535},
|
||||
{7, 16, 47143, 55584},
|
||||
{7, 16, 47227, 55633},
|
||||
{7, 16, 47310, 55682},
|
||||
{7, 16, 47393, 55731},
|
||||
{7, 16, 47477, 55780},
|
||||
{7, 16, 47561, 55830},
|
||||
{7, 16, 47645, 55879},
|
||||
{7, 16, 47729, 55928},
|
||||
{7, 16, 47813, 55977},
|
||||
{7, 16, 47897, 56027},
|
||||
{7, 16, 47982, 56076},
|
||||
{7, 16, 48066, 56125},
|
||||
{7, 16, 48151, 56175},
|
||||
{7, 16, 48236, 56225},
|
||||
{7, 16, 48321, 56274},
|
||||
{7, 16, 48406, 56323},
|
||||
{7, 16, 48491, 56373},
|
||||
{7, 16, 48576, 56422},
|
||||
{7, 16, 48662, 56472},
|
||||
{7, 16, 48748, 56522},
|
||||
{7, 16, 48833, 56571},
|
||||
{7, 16, 48919, 56621},
|
||||
{7, 16, 49005, 56671},
|
||||
{7, 16, 49091, 56721},
|
||||
{7, 16, 49152, 56756},
|
||||
{7, 16, 49178, 56771},
|
||||
{7, 16, 49264, 56820},
|
||||
{7, 16, 49350, 56870},
|
||||
{7, 16, 49437, 56920},
|
||||
{7, 16, 49524, 56970},
|
||||
{7, 16, 49611, 57020},
|
||||
{7, 16, 49698, 57070},
|
||||
{7, 16, 49785, 57120},
|
||||
{7, 16, 49873, 57171},
|
||||
{7, 16, 49960, 57220},
|
||||
{7, 16, 50048, 57271},
|
||||
{7, 16, 50135, 57321},
|
||||
{7, 16, 50223, 57371},
|
||||
{7, 16, 50311, 57421},
|
||||
{7, 16, 50399, 57471},
|
||||
{7, 16, 50488, 57522},
|
||||
{7, 16, 50576, 57572},
|
||||
{7, 16, 50665, 57623},
|
||||
{7, 16, 50753, 57673},
|
||||
{7, 16, 50842, 57723},
|
||||
{7, 16, 50931, 57774},
|
||||
{7, 16, 51020, 57824},
|
||||
{7, 16, 51109, 57875},
|
||||
{7, 16, 51199, 57926},
|
||||
{7, 16, 51288, 57976},
|
||||
{7, 16, 51378, 58027},
|
||||
{7, 16, 51468, 58078},
|
||||
{7, 16, 51558, 58128},
|
||||
{7, 16, 51648, 58179},
|
||||
{7, 16, 51738, 58230},
|
||||
{7, 16, 51828, 58280},
|
||||
{7, 16, 51919, 58331},
|
||||
{7, 16, 52009, 58382},
|
||||
{7, 16, 52100, 58433},
|
||||
{7, 16, 52191, 58484},
|
||||
{7, 16, 52282, 58535},
|
||||
{7, 16, 52373, 58586},
|
||||
{7, 16, 52464, 58637},
|
||||
{7, 16, 52556, 58688},
|
||||
{7, 16, 52647, 58739},
|
||||
{7, 16, 52739, 58790},
|
||||
{7, 16, 52831, 58842},
|
||||
{7, 16, 52923, 58893},
|
||||
{7, 16, 53015, 58944},
|
||||
{7, 16, 53107, 58995},
|
||||
{7, 16, 53200, 59047},
|
||||
{7, 16, 53292, 59098},
|
||||
{7, 16, 53385, 59149},
|
||||
{7, 16, 53478, 59201},
|
||||
{7, 16, 53571, 59252},
|
||||
{7, 16, 53664, 59304},
|
||||
{7, 16, 53757, 59355},
|
||||
{7, 16, 53851, 59407},
|
||||
{7, 16, 53944, 59458},
|
||||
{7, 16, 54038, 59510},
|
||||
{7, 16, 54132, 59562},
|
||||
{7, 16, 54226, 59613},
|
||||
{7, 16, 54320, 59665},
|
||||
{7, 16, 54414, 59717},
|
||||
{7, 16, 54508, 59768},
|
||||
{7, 16, 54603, 59820},
|
||||
{7, 16, 54698, 59872},
|
||||
{7, 16, 54792, 59924},
|
||||
{7, 16, 54887, 59976},
|
||||
{7, 16, 54983, 60028},
|
||||
{7, 16, 55078, 60080},
|
||||
{7, 16, 55173, 60132},
|
||||
{7, 16, 55269, 60184},
|
||||
{7, 16, 55365, 60236},
|
||||
{7, 16, 55460, 60288},
|
||||
{7, 16, 55556, 60340},
|
||||
{7, 16, 55652, 60392},
|
||||
{7, 16, 55749, 60445},
|
||||
{7, 16, 55845, 60497},
|
||||
{7, 16, 55942, 60549},
|
||||
{7, 16, 56038, 60601},
|
||||
{7, 16, 56135, 60654},
|
||||
{7, 16, 56232, 60706},
|
||||
{7, 16, 56330, 60759},
|
||||
{7, 16, 56427, 60811},
|
||||
{7, 16, 56524, 60863},
|
||||
{7, 16, 56622, 60916},
|
||||
{7, 16, 56720, 60969},
|
||||
{7, 16, 56818, 61022},
|
||||
{7, 16, 56916, 61074},
|
||||
{7, 16, 57014, 61127},
|
||||
{7, 16, 57112, 61179},
|
||||
{7, 16, 57211, 61232},
|
||||
{7, 16, 57309, 61285},
|
||||
{7, 16, 57408, 61338},
|
||||
{7, 16, 57507, 61390},
|
||||
{7, 16, 57606, 61443},
|
||||
{7, 16, 57705, 61496},
|
||||
{7, 16, 57805, 61549},
|
||||
{7, 16, 57904, 61602},
|
||||
{7, 16, 58004, 61655},
|
||||
{7, 16, 58104, 61708},
|
||||
{7, 16, 58204, 61761},
|
||||
{7, 16, 58304, 61814},
|
||||
{7, 16, 58404, 61867},
|
||||
{7, 16, 58504, 61920},
|
||||
{7, 16, 58605, 61974},
|
||||
{7, 16, 58706, 62027},
|
||||
{7, 16, 58807, 62080},
|
||||
{7, 16, 58908, 62134},
|
||||
{7, 16, 59009, 62187},
|
||||
{7, 16, 59110, 62240},
|
||||
{7, 16, 59212, 62294},
|
||||
{7, 16, 59313, 62347},
|
||||
{7, 16, 59415, 62400},
|
||||
{7, 16, 59517, 62454},
|
||||
{7, 16, 59619, 62508},
|
||||
{7, 16, 59722, 62561},
|
||||
{7, 16, 59824, 62615},
|
||||
{7, 16, 59927, 62669},
|
||||
{7, 16, 60029, 62722},
|
||||
{7, 16, 60132, 62776},
|
||||
{7, 16, 60235, 62830},
|
||||
{7, 16, 60338, 62883},
|
||||
{7, 16, 60442, 62937},
|
||||
{7, 16, 60545, 62991},
|
||||
{7, 16, 60649, 63045},
|
||||
{7, 16, 60753, 63099},
|
||||
{7, 16, 60857, 63153},
|
||||
{7, 16, 60961, 63207},
|
||||
{7, 16, 61065, 63261},
|
||||
{7, 16, 61169, 63315},
|
||||
{7, 16, 61274, 63369},
|
||||
{7, 16, 61379, 63423},
|
||||
{7, 16, 61484, 63478},
|
||||
{7, 16, 61589, 63532},
|
||||
{7, 16, 61694, 63586},
|
||||
{7, 16, 61799, 63640},
|
||||
{7, 16, 61905, 63695},
|
||||
{7, 16, 62010, 63749},
|
||||
{7, 16, 62116, 63803},
|
||||
{7, 16, 62222, 63858},
|
||||
{7, 16, 62328, 63912},
|
||||
{7, 16, 62435, 63967},
|
||||
{7, 16, 62541, 64021},
|
||||
{7, 16, 62648, 64076},
|
||||
{7, 16, 62755, 64130},
|
||||
{7, 16, 62862, 64185},
|
||||
{7, 16, 62969, 64240},
|
||||
{7, 16, 63076, 64294},
|
||||
{7, 16, 63183, 64349},
|
||||
{7, 16, 63291, 64404},
|
||||
{7, 16, 63399, 64459},
|
||||
{7, 16, 63507, 64514},
|
||||
{7, 16, 63615, 64568},
|
||||
{7, 16, 63723, 64623},
|
||||
{7, 16, 63831, 64678},
|
||||
{7, 16, 63940, 64733},
|
||||
{7, 16, 64049, 64788},
|
||||
{7, 16, 64158, 64843},
|
||||
{7, 16, 64267, 64898},
|
||||
{7, 16, 64376, 64953},
|
||||
{7, 16, 64485, 65008},
|
||||
{7, 16, 64595, 65064},
|
||||
{7, 16, 64704, 65119},
|
||||
{7, 16, 64814, 65174},
|
||||
{7, 16, 64924, 65229},
|
||||
{7, 16, 65034, 65285},
|
||||
{7, 16, 65145, 65340},
|
||||
{7, 16, 65255, 65395},
|
||||
{7, 16, 65366, 65451},
|
||||
{7, 16, 65477, 65506},
|
||||
{7, 16, 65534, 65535},
|
||||
{7, 16, 65536, 65536},
|
||||
{7, 20, 524288, 741455},
|
||||
{7, 20, 786432, 908093},
|
||||
{7, 20, 1048576, 1048576},
|
||||
{7, 24, 8388608, 11863283},
|
||||
{7, 24, 12582912, 14529495},
|
||||
{7, 24, 16777216, 16777216},
|
||||
{7, 28, 134217728, 189812531},
|
||||
{7, 28, 201326592, 232471924},
|
||||
{7, 28, 268435456, 268435456},
|
||||
{7, 32, 2147483648, 3037000500},
|
||||
{7, 32, 3221225472, 3719550787},
|
||||
{7, 32, 4294967296, 4294967296},
|
||||
{8, 8, 0, -1},
|
||||
{8, 8, 128, 115},
|
||||
{8, 8, 256, 175},
|
||||
{8, 12, 0, 0},
|
||||
{8, 12, 2048, 2369},
|
||||
{8, 12, 4096, 3188},
|
||||
{8, 16, 0, 0},
|
||||
{8, 16, 4096, 7972},
|
||||
{8, 16, 12288, 22372},
|
||||
{8, 16, 20480, 33324},
|
||||
{8, 16, 28672, 40872},
|
||||
{8, 16, 32768, 43652},
|
||||
{8, 16, 36864, 45935},
|
||||
{8, 16, 45056, 49396},
|
||||
{8, 16, 53248, 51855},
|
||||
{8, 16, 61440, 53673},
|
||||
{8, 16, 65536, 54414},
|
||||
{8, 20, 0, 0},
|
||||
{8, 20, 524288, 761877},
|
||||
{8, 20, 1048576, 904503},
|
||||
{8, 24, 0, 0},
|
||||
{8, 24, 8388608, 12910305},
|
||||
{8, 24, 16777216, 14840864},
|
||||
{8, 28, 0, 0},
|
||||
{8, 28, 134217728, 215042007},
|
||||
{8, 28, 268435456, 241727147},
|
||||
{8, 32, 0, 0},
|
||||
{8, 32, 2147483648, 3543989916},
|
||||
{8, 32, 4294967296, 3919432266},
|
||||
{9, 8, 0, 256},
|
||||
{9, 8, 128, 277},
|
||||
{9, 8, 256, 362},
|
||||
{9, 12, 0, 4096},
|
||||
{9, 12, 2048, 4433},
|
||||
{9, 12, 4096, 5793},
|
||||
{9, 16, 0, 65536},
|
||||
{9, 16, 682, 65538},
|
||||
{9, 16, 2046, 65556},
|
||||
{9, 16, 3408, 65591},
|
||||
{9, 16, 4768, 65643},
|
||||
{9, 16, 6123, 65713},
|
||||
{9, 16, 7474, 65800},
|
||||
{9, 16, 8819, 65904},
|
||||
{9, 16, 10157, 66025},
|
||||
{9, 16, 11488, 66162},
|
||||
{9, 16, 12810, 66316},
|
||||
{9, 16, 14123, 66486},
|
||||
{9, 16, 15426, 66672},
|
||||
{9, 16, 16718, 66874},
|
||||
{9, 16, 17999, 67091},
|
||||
{9, 16, 19268, 67323},
|
||||
{9, 16, 20526, 67570},
|
||||
{9, 16, 21771, 67832},
|
||||
{9, 16, 23003, 68108},
|
||||
{9, 16, 24222, 68398},
|
||||
{9, 16, 25427, 68701},
|
||||
{9, 16, 26619, 69018},
|
||||
{9, 16, 27798, 69349},
|
||||
{9, 16, 28962, 69692},
|
||||
{9, 16, 30113, 70048},
|
||||
{9, 16, 31250, 70417},
|
||||
{9, 16, 32373, 70798},
|
||||
{9, 16, 32768, 70936},
|
||||
{9, 16, 33482, 71191},
|
||||
{9, 16, 34577, 71595},
|
||||
{9, 16, 35659, 72012},
|
||||
{9, 16, 36726, 72440},
|
||||
{9, 16, 37780, 72879},
|
||||
{9, 16, 38820, 73329},
|
||||
{9, 16, 39847, 73791},
|
||||
{9, 16, 40860, 74263},
|
||||
{9, 16, 41861, 74746},
|
||||
{9, 16, 42848, 75240},
|
||||
{9, 16, 43822, 75743},
|
||||
{9, 16, 44783, 76257},
|
||||
{9, 16, 45732, 76782},
|
||||
{9, 16, 46668, 77316},
|
||||
{9, 16, 47592, 77861},
|
||||
{9, 16, 48503, 78414},
|
||||
{9, 16, 49403, 78979},
|
||||
{9, 16, 50290, 79552},
|
||||
{9, 16, 51166, 80135},
|
||||
{9, 16, 52030, 80728},
|
||||
{9, 16, 52883, 81330},
|
||||
{9, 16, 53725, 81942},
|
||||
{9, 16, 54555, 82562},
|
||||
{9, 16, 55375, 83192},
|
||||
{9, 16, 56183, 83831},
|
||||
{9, 16, 56982, 84480},
|
||||
{9, 16, 57769, 85137},
|
||||
{9, 16, 58547, 85804},
|
||||
{9, 16, 59314, 86480},
|
||||
{9, 16, 60071, 87164},
|
||||
{9, 16, 60818, 87857},
|
||||
{9, 16, 61556, 88560},
|
||||
{9, 16, 62284, 89271},
|
||||
{9, 16, 63002, 89991},
|
||||
{9, 16, 63711, 90720},
|
||||
{9, 16, 64412, 91458},
|
||||
{9, 16, 65103, 92205},
|
||||
{9, 16, 65491, 92632},
|
||||
{9, 16, 65536, 92682},
|
||||
{9, 20, 0, 1048576},
|
||||
{9, 20, 524288, 1134970},
|
||||
{9, 20, 1048576, 1482910},
|
||||
{9, 24, 0, 16777216},
|
||||
{9, 24, 8388608, 18159528},
|
||||
{9, 24, 16777216, 23726566},
|
||||
{9, 28, 0, 268435456},
|
||||
{9, 28, 134217728, 290552444},
|
||||
{9, 28, 268435456, 379625062},
|
||||
{9, 32, 0, 4294967296},
|
||||
{9, 32, 2147483648, 4648839102},
|
||||
{9, 32, 4294967296, 6074001000},
|
||||
{10, 8, 0, 0},
|
||||
{10, 8, 128, 17},
|
||||
{10, 8, 256, 36},
|
||||
{10, 12, 0, 0},
|
||||
{10, 12, 2048, 273},
|
||||
{10, 12, 4096, 577},
|
||||
{10, 16, 0, 0},
|
||||
{10, 16, 3251, 426},
|
||||
{10, 16, 9023, 1183},
|
||||
{10, 16, 13804, 1813},
|
||||
{10, 16, 18166, 2391},
|
||||
{10, 16, 22259, 2938},
|
||||
{10, 16, 26152, 3463},
|
||||
{10, 16, 29884, 3971},
|
||||
{10, 16, 32768, 4368},
|
||||
{10, 16, 33482, 4467},
|
||||
{10, 16, 36964, 4952},
|
||||
{10, 16, 40344, 5429},
|
||||
{10, 16, 43632, 5899},
|
||||
{10, 16, 46835, 6364},
|
||||
{10, 16, 49961, 6824},
|
||||
{10, 16, 53014, 7281},
|
||||
{10, 16, 55999, 7735},
|
||||
{10, 16, 58919, 8186},
|
||||
{10, 16, 61778, 8636},
|
||||
{10, 16, 64365, 9049},
|
||||
{10, 16, 65536, 9239},
|
||||
{10, 20, 0, 0},
|
||||
{10, 20, 524288, 69884},
|
||||
{10, 20, 1048576, 147822},
|
||||
{10, 24, 0, 0},
|
||||
{10, 24, 8388608, 1118148},
|
||||
{10, 24, 16777216, 2365152},
|
||||
{10, 28, 0, 0},
|
||||
{10, 28, 134217728, 17890375},
|
||||
{10, 28, 268435456, 37842425},
|
||||
{10, 32, 0, -1},
|
||||
{10, 32, 2147483648, 286245999},
|
||||
{10, 32, 4294967296, 605478795},
|
||||
{11, 8, 0, 0},
|
||||
{11, 8, 128, -21},
|
||||
{11, 8, 256, -38},
|
||||
{11, 12, 0, 0},
|
||||
{11, 12, 2048, -332},
|
||||
{11, 12, 4096, -611},
|
||||
{11, 16, 0, 0},
|
||||
{11, 16, 2555, -426},
|
||||
{11, 16, 7096, -1181},
|
||||
{11, 16, 10875, -1807},
|
||||
{11, 16, 14344, -2377},
|
||||
{11, 16, 17622, -2912},
|
||||
{11, 16, 20767, -3421},
|
||||
{11, 16, 23812, -3908},
|
||||
{11, 16, 26778, -4378},
|
||||
{11, 16, 29683, -4831},
|
||||
{11, 16, 32539, -5271},
|
||||
{11, 16, 32768, -5306},
|
||||
{11, 16, 35354, -5698},
|
||||
{11, 16, 38136, -6114},
|
||||
{11, 16, 40893, -6518},
|
||||
{11, 16, 43629, -6912},
|
||||
{11, 16, 46349, -7297},
|
||||
{11, 16, 49058, -7672},
|
||||
{11, 16, 51760, -8038},
|
||||
{11, 16, 54457, -8395},
|
||||
{11, 16, 57155, -8743},
|
||||
{11, 16, 59855, -9084},
|
||||
{11, 16, 62561, -9416},
|
||||
{11, 16, 64726, -9675},
|
||||
{11, 16, 65536, -9770},
|
||||
{11, 20, 0, 0},
|
||||
{11, 20, 524288, -84898},
|
||||
{11, 20, 1048576, -156324},
|
||||
{11, 24, 0, 0},
|
||||
{11, 24, 8388608, -1358371},
|
||||
{11, 24, 16777216, -2501179},
|
||||
{11, 28, 0, 0},
|
||||
{11, 28, 134217728, -21733943},
|
||||
{11, 28, 268435456, -40018860},
|
||||
{11, 32, 0, 0},
|
||||
{11, 32, 2147483648, -347743095},
|
||||
{11, 32, 4294967296, -640301764},
|
||||
13
test/tests/random_odr_tu.cpp
Normal file
13
test/tests/random_odr_tu.cpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "dpf/random.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dpf_rng_test
|
||||
{
|
||||
|
||||
std::uint64_t sample_from_other_tu()
|
||||
{
|
||||
return dpf::uniform_sample<std::uint64_t>();
|
||||
}
|
||||
|
||||
} // namespace dpf_rng_test
|
||||
396
test/tests/random_test.cpp
Normal file
396
test/tests/random_test.cpp
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
#include "dpf/random.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dpf/bit.hpp"
|
||||
#include "dpf/xor_wrapper.hpp"
|
||||
#include "simde/simde/x86/avx2.h"
|
||||
|
||||
namespace dpf_rng_test
|
||||
{
|
||||
std::uint64_t sample_from_other_tu();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct HookState
|
||||
{
|
||||
int calls = 0;
|
||||
std::size_t last_n = 0;
|
||||
unsigned char byte = 0xA5;
|
||||
bool use_typed = false;
|
||||
std::int32_t typed = 1;
|
||||
std::vector<std::size_t> sizes;
|
||||
const unsigned char * script = nullptr;
|
||||
std::size_t script_i = 0;
|
||||
};
|
||||
|
||||
HookState g_hook;
|
||||
|
||||
void reset_hook()
|
||||
{
|
||||
g_hook = HookState{};
|
||||
dpf::detail::uniform_bytes_hook = nullptr;
|
||||
}
|
||||
|
||||
void test_hook(void * dst, std::size_t n)
|
||||
{
|
||||
++g_hook.calls;
|
||||
g_hook.last_n = n;
|
||||
g_hook.sizes.push_back(n);
|
||||
if (g_hook.script != nullptr)
|
||||
{
|
||||
std::memcpy(dst, g_hook.script + g_hook.script_i, n);
|
||||
g_hook.script_i += n;
|
||||
return;
|
||||
}
|
||||
if (g_hook.use_typed && n == sizeof(g_hook.typed))
|
||||
{
|
||||
std::memcpy(dst, &g_hook.typed, n);
|
||||
return;
|
||||
}
|
||||
std::memset(dst, g_hook.byte, n);
|
||||
}
|
||||
|
||||
void fill_byte(void * dst, std::size_t n, unsigned char byte)
|
||||
{
|
||||
std::memset(dst, byte, n);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T load_bytes(unsigned char byte)
|
||||
{
|
||||
T value;
|
||||
fill_byte(&value, sizeof(value), byte);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool same_bytes(const void * a, const void * b, std::size_t n)
|
||||
{
|
||||
return std::memcmp(a, b, n) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void expect_reconstruct_unsigned(T secret)
|
||||
{
|
||||
auto [share0, share1] = dpf::additively_share(secret);
|
||||
EXPECT_EQ(dpf::reconstruct(share0, share1), secret);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void expect_reconstruct_signed(T secret)
|
||||
{
|
||||
auto [share0, share1] = dpf::additively_share(secret);
|
||||
using U = std::make_unsigned_t<T>;
|
||||
EXPECT_EQ(static_cast<U>(dpf::reconstruct(share0, share1)),
|
||||
static_cast<U>(secret));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class RandomTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void TearDown() override
|
||||
{
|
||||
reset_hook();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(RandomTest, UniformFillReturnsTheSameObject)
|
||||
{
|
||||
std::uint32_t value = 0;
|
||||
EXPECT_EQ(&dpf::uniform_fill(value), &value);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, HookOverwritesEveryByte)
|
||||
{
|
||||
dpf::detail::uniform_bytes_hook = test_hook;
|
||||
g_hook.byte = 0xA5;
|
||||
|
||||
struct Padded
|
||||
{
|
||||
std::uint8_t a;
|
||||
std::uint32_t b;
|
||||
};
|
||||
Padded padded = dpf::uniform_sample<Padded>();
|
||||
EXPECT_EQ(g_hook.calls, 1);
|
||||
EXPECT_EQ(g_hook.last_n, sizeof(Padded));
|
||||
auto expected = load_bytes<Padded>(0xA5);
|
||||
EXPECT_TRUE(same_bytes(&padded, &expected, sizeof(Padded)));
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, HookSeesTheObjectSize)
|
||||
{
|
||||
dpf::detail::uniform_bytes_hook = test_hook;
|
||||
g_hook.byte = 0x3C;
|
||||
|
||||
auto byte = dpf::uniform_sample<std::uint8_t>();
|
||||
auto block = dpf::uniform_sample<simde__m128i>();
|
||||
std::array<unsigned char, 32> wide{};
|
||||
dpf::uniform_fill(wide);
|
||||
|
||||
EXPECT_EQ(byte, static_cast<std::uint8_t>(0x3C));
|
||||
EXPECT_EQ(g_hook.sizes, (std::vector<std::size_t>{
|
||||
1u, sizeof(simde__m128i), 32u}));
|
||||
auto expected_block = load_bytes<simde__m128i>(0x3C);
|
||||
EXPECT_TRUE(same_bytes(&block, &expected_block, sizeof(block)));
|
||||
for (unsigned char b : wide)
|
||||
EXPECT_EQ(b, static_cast<unsigned char>(0x3C));
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, ClearingTheHookReadsTheDeviceAgain)
|
||||
{
|
||||
dpf::detail::uniform_bytes_hook = [](void * dst, std::size_t n)
|
||||
{
|
||||
fill_byte(dst, n, 0x11);
|
||||
};
|
||||
EXPECT_EQ(dpf::uniform_sample<std::uint32_t>(), 0x11111111u);
|
||||
dpf::detail::uniform_bytes_hook = nullptr;
|
||||
|
||||
std::set<std::array<unsigned char, 16>> draws;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
std::array<unsigned char, 16> sample{};
|
||||
dpf::uniform_fill(sample);
|
||||
draws.insert(sample);
|
||||
bool nonzero = false;
|
||||
for (unsigned char b : sample)
|
||||
nonzero = nonzero || b != 0;
|
||||
EXPECT_TRUE(nonzero);
|
||||
}
|
||||
EXPECT_EQ(draws.size(), 8u);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, HookIsThreadLocal)
|
||||
{
|
||||
dpf::detail::uniform_bytes_hook = [](void * dst, std::size_t n)
|
||||
{
|
||||
fill_byte(dst, n, 0x11);
|
||||
};
|
||||
|
||||
std::uint32_t other = 0;
|
||||
std::thread worker([&]()
|
||||
{
|
||||
dpf::detail::uniform_bytes_hook = [](void * dst, std::size_t n)
|
||||
{
|
||||
fill_byte(dst, n, 0x22);
|
||||
};
|
||||
other = dpf::uniform_sample<std::uint32_t>();
|
||||
dpf::detail::uniform_bytes_hook = nullptr;
|
||||
});
|
||||
worker.join();
|
||||
|
||||
EXPECT_EQ(dpf::uniform_sample<std::uint32_t>(), 0x11111111u);
|
||||
EXPECT_EQ(other, 0x22222222u);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, BooleanSamplesUseOnlyTheLowBit)
|
||||
{
|
||||
const unsigned char raw[] = {0x00, 0x02, 0xFF};
|
||||
g_hook.script = raw;
|
||||
dpf::detail::uniform_bytes_hook = test_hook;
|
||||
|
||||
EXPECT_FALSE(dpf::uniform_sample<bool>());
|
||||
EXPECT_FALSE(dpf::uniform_sample<bool>());
|
||||
EXPECT_TRUE(dpf::uniform_sample<bool>());
|
||||
|
||||
g_hook.script_i = 0;
|
||||
EXPECT_EQ(dpf::uniform_sample<dpf::bit>(), dpf::bit::zero);
|
||||
EXPECT_EQ(dpf::uniform_sample<dpf::bit>(), dpf::bit::zero);
|
||||
EXPECT_EQ(dpf::uniform_sample<dpf::bit>(), dpf::bit::one);
|
||||
EXPECT_EQ(g_hook.calls, 6);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, DeviceBooleanSamplesAreBothValues)
|
||||
{
|
||||
bool saw_false = false;
|
||||
bool saw_true = false;
|
||||
bool saw_zero = false;
|
||||
bool saw_one = false;
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
bool bit = dpf::uniform_sample<bool>();
|
||||
saw_false = saw_false || !bit;
|
||||
saw_true = saw_true || bit;
|
||||
dpf::bit as_bit = dpf::uniform_sample<dpf::bit>();
|
||||
EXPECT_TRUE(as_bit == dpf::bit::zero || as_bit == dpf::bit::one);
|
||||
saw_zero = saw_zero || as_bit == dpf::bit::zero;
|
||||
saw_one = saw_one || as_bit == dpf::bit::one;
|
||||
}
|
||||
EXPECT_TRUE(saw_false);
|
||||
EXPECT_TRUE(saw_true);
|
||||
EXPECT_TRUE(saw_zero);
|
||||
EXPECT_TRUE(saw_one);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, AdditiveSharesReconstructUnsigned)
|
||||
{
|
||||
expect_reconstruct_unsigned<std::uint8_t>(0);
|
||||
expect_reconstruct_unsigned<std::uint8_t>(1);
|
||||
expect_reconstruct_unsigned<std::uint8_t>(255);
|
||||
expect_reconstruct_unsigned<std::uint32_t>(0);
|
||||
expect_reconstruct_unsigned<std::uint32_t>(1);
|
||||
expect_reconstruct_unsigned<std::uint32_t>(0xFFFFFFFFu);
|
||||
expect_reconstruct_unsigned<std::uint64_t>(0);
|
||||
expect_reconstruct_unsigned<std::uint64_t>(
|
||||
std::numeric_limits<std::uint64_t>::max());
|
||||
|
||||
dpf::detail::uniform_bytes_hook = test_hook;
|
||||
g_hook.byte = 0xFF;
|
||||
auto [share0, share1] = dpf::additively_share<std::uint32_t>(0);
|
||||
EXPECT_EQ(g_hook.calls, 1);
|
||||
EXPECT_EQ(share0.raw(), 0xFFFFFFFFu);
|
||||
EXPECT_EQ(share1.raw(), 1u);
|
||||
EXPECT_EQ(dpf::reconstruct(share0, share1), 0u);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, AdditiveSharesReconstructSignedExtremes)
|
||||
{
|
||||
dpf::detail::uniform_bytes_hook = test_hook;
|
||||
g_hook.use_typed = true;
|
||||
g_hook.typed = 1;
|
||||
|
||||
constexpr auto secret = std::numeric_limits<std::int32_t>::min();
|
||||
auto [share0, share1] = dpf::additively_share(secret);
|
||||
EXPECT_EQ(share0.raw(), 1);
|
||||
using U = std::uint32_t;
|
||||
EXPECT_EQ(static_cast<U>(dpf::reconstruct(share0, share1)),
|
||||
static_cast<U>(secret));
|
||||
|
||||
dpf::detail::uniform_bytes_hook = nullptr;
|
||||
expect_reconstruct_signed<std::int8_t>(std::numeric_limits<std::int8_t>::min());
|
||||
expect_reconstruct_signed<std::int8_t>(std::numeric_limits<std::int8_t>::max());
|
||||
expect_reconstruct_signed<std::int8_t>(-1);
|
||||
expect_reconstruct_signed<std::int32_t>(secret);
|
||||
expect_reconstruct_signed<std::int32_t>(std::numeric_limits<std::int32_t>::max());
|
||||
expect_reconstruct_signed<std::int32_t>(-1);
|
||||
expect_reconstruct_signed<std::int32_t>(0);
|
||||
expect_reconstruct_signed<std::int64_t>(std::numeric_limits<std::int64_t>::min());
|
||||
expect_reconstruct_signed<std::int64_t>(std::numeric_limits<std::int64_t>::max());
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, AdditiveSharesReconstructBitAndXorGroup)
|
||||
{
|
||||
for (dpf::bit secret : {dpf::bit::zero, dpf::bit::one})
|
||||
{
|
||||
auto [share0, share1] = dpf::additively_share(secret);
|
||||
EXPECT_TRUE(share0.raw() == dpf::bit::zero || share0.raw() == dpf::bit::one);
|
||||
EXPECT_TRUE(share1.raw() == dpf::bit::zero || share1.raw() == dpf::bit::one);
|
||||
EXPECT_EQ(dpf::reconstruct(share0, share1), secret);
|
||||
}
|
||||
|
||||
dpf::xor_wrapper<std::uint32_t> secret{0xA5A5A5A5u};
|
||||
auto [share0, share1] = dpf::additively_share(secret);
|
||||
EXPECT_EQ(dpf::reconstruct(share0, share1), secret);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, AdditiveShareDrawsOnce)
|
||||
{
|
||||
dpf::detail::uniform_bytes_hook = test_hook;
|
||||
g_hook.byte = 0x01;
|
||||
auto shares = dpf::additively_share<std::uint32_t>(0x10u);
|
||||
EXPECT_EQ(g_hook.calls, 1);
|
||||
EXPECT_EQ(shares.first.raw(), 0x01010101u);
|
||||
EXPECT_EQ(dpf::reconstruct(shares.first, shares.second), 0x10u);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, ForkedProcessesDoNotRepeatEntropy)
|
||||
{
|
||||
// A buffered stdio read of the device copies the unread buffer into the
|
||||
// child. Prime the generator, then compare the next draw on each side.
|
||||
(void)dpf::uniform_sample<std::uint64_t>();
|
||||
|
||||
int fds[2];
|
||||
ASSERT_EQ(::pipe(fds), 0);
|
||||
pid_t pid = ::fork();
|
||||
ASSERT_NE(pid, -1);
|
||||
if (pid == 0)
|
||||
{
|
||||
::close(fds[0]);
|
||||
auto sample = dpf::uniform_sample<std::array<unsigned char, 32>>();
|
||||
ssize_t wrote = ::write(fds[1], sample.data(), sample.size());
|
||||
::_exit(wrote == static_cast<ssize_t>(sample.size()) ? 0 : 1);
|
||||
}
|
||||
|
||||
::close(fds[1]);
|
||||
auto parent = dpf::uniform_sample<std::array<unsigned char, 32>>();
|
||||
std::array<unsigned char, 32> child{};
|
||||
std::size_t got = 0;
|
||||
while (got < child.size())
|
||||
{
|
||||
ssize_t n = ::read(fds[0], child.data() + got, child.size() - got);
|
||||
if (n <= 0)
|
||||
break;
|
||||
got += static_cast<std::size_t>(n);
|
||||
}
|
||||
::close(fds[0]);
|
||||
int status = 0;
|
||||
ASSERT_EQ(::waitpid(pid, &status, 0), pid);
|
||||
ASSERT_TRUE(WIFEXITED(status));
|
||||
ASSERT_EQ(WEXITSTATUS(status), 0);
|
||||
ASSERT_EQ(got, child.size());
|
||||
EXPECT_FALSE(same_bytes(parent.data(), child.data(), parent.size()));
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, ConcurrentReadsStayWellFormed)
|
||||
{
|
||||
constexpr int threads = 4;
|
||||
constexpr int draws = 128;
|
||||
std::vector<std::vector<std::uint64_t>> results(threads);
|
||||
std::vector<std::thread> workers;
|
||||
workers.reserve(threads);
|
||||
for (int t = 0; t < threads; ++t)
|
||||
{
|
||||
workers.emplace_back([&, t]()
|
||||
{
|
||||
results[t].reserve(draws);
|
||||
for (int i = 0; i < draws; ++i)
|
||||
results[t].push_back(dpf::uniform_sample<std::uint64_t>());
|
||||
});
|
||||
}
|
||||
for (auto & worker : workers)
|
||||
worker.join();
|
||||
|
||||
std::set<std::uint64_t> unique;
|
||||
for (const auto & row : results)
|
||||
{
|
||||
EXPECT_EQ(row.size(), static_cast<std::size_t>(draws));
|
||||
unique.insert(row.begin(), row.end());
|
||||
}
|
||||
EXPECT_EQ(unique.size(), static_cast<std::size_t>(threads * draws));
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, OtherTranslationUnitCanSample)
|
||||
{
|
||||
auto here = dpf::uniform_sample<std::uint64_t>();
|
||||
auto there = dpf_rng_test::sample_from_other_tu();
|
||||
EXPECT_NE(here, there);
|
||||
}
|
||||
|
||||
TEST_F(RandomTest, DeviceLowBitTakesBothValues)
|
||||
{
|
||||
// Doerner–Shelat pad bits are `uniform_sample<unsigned char>() & 1`.
|
||||
bool saw0 = false;
|
||||
bool saw1 = false;
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
auto bit = static_cast<unsigned>(dpf::uniform_sample<unsigned char>() & 1u);
|
||||
saw0 = saw0 || bit == 0u;
|
||||
saw1 = saw1 || bit == 1u;
|
||||
}
|
||||
EXPECT_TRUE(saw0);
|
||||
EXPECT_TRUE(saw1);
|
||||
}
|
||||
143
test/tests/secret_share_test.cpp
Normal file
143
test/tests/secret_share_test.cpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
TEST(SecretShare, LayoutMatchesValueType)
|
||||
{
|
||||
using T = std::uint64_t;
|
||||
EXPECT_EQ(sizeof(dpf::additive_share<T, 0>), sizeof(T));
|
||||
EXPECT_EQ(sizeof(dpf::subtractive_share<T, 1>), sizeof(T));
|
||||
EXPECT_TRUE((std::is_trivially_copyable_v<dpf::additive_share<T, 0>>));
|
||||
EXPECT_TRUE((std::is_standard_layout_v<dpf::subtractive_share<T, 1>>));
|
||||
}
|
||||
|
||||
TEST(SecretShare, PlaintextSplitOpens)
|
||||
{
|
||||
const std::uint32_t secret = 0xdeadbeefu;
|
||||
auto [a0, a1] = dpf::make_additive_shares(secret);
|
||||
EXPECT_EQ(dpf::reconstruct(a0, a1), secret);
|
||||
EXPECT_EQ(a1.raw(), 0u);
|
||||
|
||||
auto [s0, s1] = dpf::make_subtractive_shares(secret);
|
||||
EXPECT_EQ(dpf::reconstruct(s0, s1), secret);
|
||||
EXPECT_EQ(s1.raw(), 0u);
|
||||
}
|
||||
|
||||
TEST(SecretShare, SameSchemeLinearCombo)
|
||||
{
|
||||
auto [a0, a1] = dpf::make_additive_shares(std::uint32_t{10});
|
||||
auto [b0, b1] = dpf::make_additive_shares(std::uint32_t{3});
|
||||
auto c0 = a0 * 2 + b0;
|
||||
auto c1 = a1 * 2 + b1;
|
||||
EXPECT_EQ(dpf::reconstruct(c0, c1), 23u);
|
||||
|
||||
auto [s0, s1] = dpf::make_subtractive_shares(std::uint32_t{10});
|
||||
auto [t0, t1] = dpf::make_subtractive_shares(std::uint32_t{3});
|
||||
auto u0 = s0 * 2 - t0;
|
||||
auto u1 = s1 * 2 - t1;
|
||||
EXPECT_EQ(dpf::reconstruct(u0, u1), 17u);
|
||||
}
|
||||
|
||||
TEST(SecretShare, CrossSchemeSigns)
|
||||
{
|
||||
auto [a0, a1] = dpf::make_additive_shares(std::int32_t{20});
|
||||
auto [s0, s1] = dpf::make_subtractive_shares(std::int32_t{7});
|
||||
|
||||
// party 0: raw add; party 1: flip the differing-scheme operand
|
||||
auto r0 = a0 + s0;
|
||||
auto r1 = a1 + s1;
|
||||
EXPECT_EQ(dpf::reconstruct(r0, r1), 27);
|
||||
|
||||
auto q0 = s0 + a0;
|
||||
auto q1 = s1 + a1;
|
||||
EXPECT_EQ(dpf::reconstruct(q0, q1), 27);
|
||||
}
|
||||
|
||||
TEST(SecretShare, PlaintextAbsorbOnParty0)
|
||||
{
|
||||
auto [s0, s1] = dpf::make_subtractive_shares(std::uint32_t{5});
|
||||
s0 += std::uint32_t{10};
|
||||
s1 += std::uint32_t{10}; // no-op for party 1
|
||||
EXPECT_EQ(dpf::reconstruct(s0, s1), 15u);
|
||||
}
|
||||
|
||||
TEST(SecretShare, AsAdditivePreservesSecret)
|
||||
{
|
||||
auto [s0, s1] = dpf::make_subtractive_shares(std::int32_t{42});
|
||||
auto a0 = s0.as_additive();
|
||||
auto a1 = s1.as_additive();
|
||||
EXPECT_EQ(dpf::reconstruct(a0, a1), 42);
|
||||
}
|
||||
|
||||
TEST(SecretShare, DpfLeafRoundTrip)
|
||||
{
|
||||
const std::uint8_t alpha = 0x2a;
|
||||
const std::uint32_t beta = 0x01020304;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, beta);
|
||||
EXPECT_TRUE(dpf::is_party_key_v<decltype(k0)>);
|
||||
EXPECT_EQ(decltype(k0)::party, 0u);
|
||||
EXPECT_EQ(decltype(k1)::party, 1u);
|
||||
|
||||
auto y0 = *dpf::eval_point(k0, alpha);
|
||||
auto y1 = *dpf::eval_point(k1, alpha);
|
||||
EXPECT_TRUE((std::is_same_v<decltype(y0), dpf::subtractive_share<std::uint32_t, 0>>));
|
||||
EXPECT_EQ(dpf::reconstruct(y0, y1), beta);
|
||||
|
||||
auto z0 = *dpf::eval_point(k0, static_cast<std::uint8_t>(alpha ^ 1));
|
||||
auto z1 = *dpf::eval_point(k1, static_cast<std::uint8_t>(alpha ^ 1));
|
||||
EXPECT_EQ(dpf::reconstruct(z0, z1), 0u);
|
||||
}
|
||||
|
||||
TEST(SecretShare, DpfXorLeafRoundTrip)
|
||||
{
|
||||
using X = dpf::xor_wrapper<std::uint32_t>;
|
||||
const std::uint8_t alpha = 7;
|
||||
const X beta{0xA5A5A5A5u};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, beta);
|
||||
auto y0 = *dpf::eval_point(k0, alpha);
|
||||
auto y1 = *dpf::eval_point(k1, alpha);
|
||||
EXPECT_EQ(dpf::reconstruct(y0, y1), beta);
|
||||
}
|
||||
|
||||
TEST(SecretShare, CmpAdditiveRoundTrip)
|
||||
{
|
||||
const std::uint32_t alpha = 100u;
|
||||
const std::uint64_t yt = 5u, yf = 9u;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::lt(yt, yf));
|
||||
const std::uint64_t mask = k0.cmp().mask;
|
||||
auto below = dpf::reconstruct(
|
||||
dpf::eval_point(dpf::cmp, k0, 50u),
|
||||
dpf::eval_point(dpf::cmp, k1, 50u)) & mask;
|
||||
auto at = dpf::reconstruct(
|
||||
dpf::eval_point(dpf::cmp, k0, alpha),
|
||||
dpf::eval_point(dpf::cmp, k1, alpha)) & mask;
|
||||
EXPECT_EQ(below, yt);
|
||||
EXPECT_EQ(at, yf);
|
||||
}
|
||||
|
||||
TEST(SecretShare, PrgExpandSubtractive)
|
||||
{
|
||||
using prg = dpf::prg::aes128;
|
||||
const auto seed0 = dpf::uniform_sample<prg::block_type>();
|
||||
const auto seed1 = dpf::uniform_sample<prg::block_type>();
|
||||
auto s0 = prg::expand<std::uint64_t, 0>(seed0, 0);
|
||||
auto s1 = prg::expand<std::uint64_t, 1>(seed1, 0);
|
||||
// Same pos, different seeds: reconstruct is raw0 - raw1 (bit pattern).
|
||||
EXPECT_EQ(dpf::reconstruct(s0, s1),
|
||||
static_cast<std::uint64_t>(s0.raw() - s1.raw()));
|
||||
|
||||
// Same seed → same bits → reconstruct 0
|
||||
auto t0 = prg::expand<std::uint32_t, 0>(seed0, 3);
|
||||
auto t1 = prg::expand<std::uint32_t, 1>(seed0, 3);
|
||||
EXPECT_EQ(dpf::reconstruct(t0, t1), 0u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
37
test/tests/setbit_index_iterable_test.cpp
Normal file
37
test/tests/setbit_index_iterable_test.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
TEST(SetbitIndexIterableTest, BasicUsage)
|
||||
{
|
||||
using input_type = uint16_t;
|
||||
using output_type = dpf::bit;
|
||||
input_type x = 0xAAAA;
|
||||
output_type y = dpf::bit::one;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
auto [buf0, iter0] = dpf::eval_full(dpf0);
|
||||
auto [buf1, iter1] = dpf::eval_full(dpf1);
|
||||
|
||||
auto setbit0 = dpf::indices_set_in(iter0),
|
||||
setbit1 = dpf::indices_set_in(iter1);
|
||||
|
||||
auto it0 = std::begin(setbit0), it0end = std::end(setbit0),
|
||||
it1 = std::begin(setbit1), it1end = std::end(setbit1);
|
||||
for (; it0 != it0end && it1 != it1end; ++it0, ++it1)
|
||||
{
|
||||
if (*it0 == x)
|
||||
{
|
||||
ASSERT_EQ(*(++it0), *it1);
|
||||
}
|
||||
else if (*it1 == x)
|
||||
{
|
||||
ASSERT_EQ(*it0, *(++it1));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(*it0, *it1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(it0, it0end);
|
||||
ASSERT_EQ(it1, it1end);
|
||||
}
|
||||
143
test/tests/signed_prefix_test.cpp
Normal file
143
test/tests/signed_prefix_test.cpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "grotto/constant_lut.hpp"
|
||||
#include "grotto/prefix_parity.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
uint64_t opened(uint64_t a, uint64_t b, uint64_t mask)
|
||||
{
|
||||
return (a + b) & mask;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
int piece_containing(T alpha, const std::array<T, N> & ends)
|
||||
{
|
||||
for (std::size_t i = 0; i + 1 < N; ++i)
|
||||
{
|
||||
if (alpha >= ends[i] && alpha < ends[i + 1])
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
return static_cast<int>(N - 1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(SignedPrefix, MatchesComparisonEvalOnEveryUint8Point)
|
||||
{
|
||||
const uint8_t alpha = 0x3c;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(uint64_t{1}));
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
std::array<uint8_t, 8> ends{0, 1, 10, alpha, 100, 200, 254, 255};
|
||||
const auto p0 = grotto::signed_prefix_parities(k0, ends);
|
||||
const auto p1 = grotto::signed_prefix_parities(k1, ends);
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const auto e0 = dpf::eval_point(dpf::cmp, k0, ends[i]);
|
||||
const auto e1 = dpf::eval_point(dpf::cmp, k1, ends[i]);
|
||||
EXPECT_EQ(p0[i], e0.raw()) << int(ends[i]);
|
||||
EXPECT_EQ(p1[i], e1.raw()) << int(ends[i]);
|
||||
EXPECT_EQ(opened(p0[i], p1[i], mask), ends[i] > alpha ? 1u : 0u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SignedPrefix, SegmentsAreOneHot)
|
||||
{
|
||||
const uint8_t alpha = 40;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(uint64_t{1}));
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
const std::array<uint8_t, 5> ends{0, 1, 10, 40, 200};
|
||||
const auto s0 = grotto::signed_segment_parities(k0, ends);
|
||||
const auto s1 = grotto::signed_segment_parities(k1, ends);
|
||||
const int hot = piece_containing(alpha, ends);
|
||||
uint64_t sum = 0;
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const uint64_t bit = opened(s0[i], s1[i], mask);
|
||||
sum = (sum + bit) & mask;
|
||||
EXPECT_EQ(bit, i == static_cast<std::size_t>(hot) ? 1u : 0u) << i;
|
||||
}
|
||||
EXPECT_EQ(sum, 1u);
|
||||
|
||||
for (uint8_t a : {uint8_t{0}, uint8_t{1}, uint8_t{9}, uint8_t{200}, uint8_t{255}})
|
||||
{
|
||||
auto [a0, a1] = dpf::make_dpf(a, dpf::gt(uint64_t{1}));
|
||||
const auto t0 = grotto::signed_segment_parities(a0, ends);
|
||||
const auto t1 = grotto::signed_segment_parities(a1, ends);
|
||||
const int where = piece_containing(a, ends);
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
EXPECT_EQ(opened(t0[i], t1[i], mask), i == static_cast<std::size_t>(where) ? 1u : 0u)
|
||||
<< "alpha=" << int(a) << " piece=" << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SignedPrefix, WholeDomainIsThePublicOne)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(uint8_t{7}, dpf::gt(uint64_t{1}));
|
||||
const std::array<uint8_t, 1> ends{0};
|
||||
const auto s0 = grotto::signed_segment_parities(k0, ends);
|
||||
const auto s1 = grotto::signed_segment_parities(k1, ends);
|
||||
EXPECT_EQ(opened(s0[0], s1[0], k0.cmp().mask), 1u);
|
||||
}
|
||||
|
||||
TEST(SignedPrefix, SignumLutIsSignCorrect)
|
||||
{
|
||||
for (int alpha = -128; alpha <= 127; ++alpha)
|
||||
{
|
||||
const auto a = static_cast<int8_t>(alpha);
|
||||
auto [k0, k1] = dpf::make_dpf(a, dpf::gt(uint64_t{1}));
|
||||
const auto lut = grotto::make_exact_constant_lut<int8_t>(
|
||||
grotto::exact_constant::signum, 0);
|
||||
ASSERT_EQ(lut.bounds.size(), 3u);
|
||||
std::array<int8_t, 3> ends{};
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
ends[i] = lut.bounds[i];
|
||||
const auto s0 = grotto::signed_segment_parities(k0, ends);
|
||||
const auto s1 = grotto::signed_segment_parities(k1, ends);
|
||||
uint64_t acc0 = 0;
|
||||
uint64_t acc1 = 0;
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
const auto coef = static_cast<uint64_t>(lut.values[i]);
|
||||
acc0 += s0[i] * coef;
|
||||
acc1 += s1[i] * coef;
|
||||
}
|
||||
const auto got = static_cast<int64_t>(acc0 + acc1);
|
||||
const int64_t want = alpha < 0 ? -1 : (alpha > 0 ? 1 : 0);
|
||||
EXPECT_EQ(got, want) << alpha;
|
||||
// The advice-bit lift is ±want. The DCF shares must not come out negated.
|
||||
if (want != 0)
|
||||
EXPECT_NE(got, -want) << alpha;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SignedPrefix, SharedPrefixAgreesWithAFreshWalk)
|
||||
{
|
||||
const uint16_t alpha = 0x0100;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(uint64_t{1}));
|
||||
// Consecutive knots share a long prefix; the cached sum must match a
|
||||
// one-knot walk.
|
||||
const std::array<uint16_t, 4> ends{0, 1, 0x0100, 0x0101};
|
||||
const auto many = grotto::signed_prefix_parities(k0, ends);
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const std::array<uint16_t, 1> one{ends[i]};
|
||||
const auto alone = grotto::signed_prefix_parities(k0, one);
|
||||
EXPECT_EQ(many[i], alone[0]) << i;
|
||||
}
|
||||
(void)k1;
|
||||
}
|
||||
|
||||
TEST(SignedPrefix, RejectsAKeyWithoutAComparison)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(uint8_t{1}, dpf::bit::one);
|
||||
const std::array<uint8_t, 2> ends{0, 1};
|
||||
EXPECT_THROW(grotto::signed_prefix_parities(k0, ends), std::invalid_argument);
|
||||
EXPECT_THROW(grotto::signed_segment_parities(k1, ends), std::invalid_argument);
|
||||
}
|
||||
2238
test/tests/stress_scenarios_test.cpp
Normal file
2238
test/tests/stress_scenarios_test.cpp
Normal file
File diff suppressed because it is too large
Load diff
1006
test/tests/types_test.cpp
Normal file
1006
test/tests/types_test.cpp
Normal file
File diff suppressed because it is too large
Load diff
619
test/tests/wildcard_test.cpp
Normal file
619
test/tests/wildcard_test.cpp
Normal file
|
|
@ -0,0 +1,619 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "asio.hpp"
|
||||
#define LIBDPF_HAS_ASIO
|
||||
#include "dpf.hpp"
|
||||
|
||||
template <std::size_t I = 0,
|
||||
typename DpfKey0,
|
||||
typename DpfKey1,
|
||||
typename ConcreteT>
|
||||
void assign_leaf(DpfKey0 & dpf0, DpfKey1 & dpf1, const ConcreteT y_shr0, const ConcreteT y_shr1)
|
||||
{
|
||||
asio::io_context io_context;
|
||||
std::thread server([&io_context, &dpf0, &y_shr0]()
|
||||
{
|
||||
asio::ip::tcp::acceptor acceptor(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), 31337));
|
||||
asio::ip::tcp::socket peer{io_context};
|
||||
asio::ip::tcp::endpoint ep{};
|
||||
acceptor.accept(peer, ep);
|
||||
auto future = dpf0.template async_assign_leaf<I>(peer, y_shr0, asio::use_future);
|
||||
io_context.run();
|
||||
future.wait();
|
||||
});
|
||||
std::thread client([&io_context, &dpf1, &y_shr1]()
|
||||
{
|
||||
asio::ip::tcp::socket peer(io_context);
|
||||
asio::ip::tcp::resolver resolver(io_context);
|
||||
asio::connect(peer, resolver.resolve("localhost", "31337"));
|
||||
auto future = dpf1.template async_assign_leaf<I>(peer, y_shr1, asio::use_future);
|
||||
io_context.run();
|
||||
future.wait();
|
||||
});
|
||||
client.join();
|
||||
server.join();
|
||||
}
|
||||
|
||||
TEST(WildcardTest, SingleLeafFailEvalBeforeVernalization)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using output_type = dpf::wildcard_value<uint32_t>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
input_type x = 0xAA;
|
||||
output_type y;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
|
||||
ASSERT_THROW(dpf::eval_point(dpf0, x), std::runtime_error);
|
||||
ASSERT_THROW(dpf::eval_point(dpf1, x), std::runtime_error);
|
||||
|
||||
input_type from = 0x33, to = 0xCC;
|
||||
ASSERT_THROW(dpf::eval_interval(dpf0, from, to), std::runtime_error);
|
||||
ASSERT_THROW(dpf::eval_interval(dpf1, from, to), std::runtime_error);
|
||||
|
||||
ASSERT_THROW(dpf::eval_full(dpf0), std::runtime_error);
|
||||
ASSERT_THROW(dpf::eval_full(dpf1), std::runtime_error);
|
||||
|
||||
std::array<input_type, 16> points{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
ASSERT_THROW(dpf::eval_sequence(dpf0, std::begin(points), std::end(points)), std::runtime_error);
|
||||
ASSERT_THROW(dpf::eval_sequence(dpf1, std::begin(points), std::end(points)), std::runtime_error);
|
||||
|
||||
ASSERT_THROW(dpf::eval_sequence_breadth_first(dpf0, std::begin(points), std::end(points)), std::runtime_error);
|
||||
ASSERT_THROW(dpf::eval_sequence_breadth_first(dpf1, std::begin(points), std::end(points)), std::runtime_error);
|
||||
|
||||
auto recipe0 = dpf::make_sequence_recipe(dpf0, std::begin(points), std::end(points));
|
||||
auto recipe1 = dpf::make_sequence_recipe(dpf1, std::begin(points), std::end(points));
|
||||
ASSERT_THROW(dpf::eval_sequence(dpf0, recipe0), std::runtime_error);
|
||||
ASSERT_THROW(dpf::eval_sequence(dpf1, recipe1), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(WildcardTest, MultiLeafFailEvalBeforeVernalization)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using output_type0 = uint32_t;
|
||||
using output_type1 = dpf::wildcard_value<uint32_t>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type0, output_type1>;
|
||||
input_type x = 0xAA;
|
||||
output_type0 y0 = 0xAAAAAAAA;
|
||||
output_type1 y1;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1);
|
||||
|
||||
ASSERT_NO_THROW((dpf::eval_point<0>(dpf0, x)));
|
||||
ASSERT_NO_THROW((dpf::eval_point<0>(dpf1, x)));
|
||||
ASSERT_THROW((dpf::eval_point<1>(dpf0, x)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_point<1>(dpf1, x)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_point<0, 1>(dpf0, x)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_point<0, 1>(dpf1, x)), std::runtime_error);
|
||||
|
||||
input_type from = 0x33, to = 0xCC;
|
||||
ASSERT_NO_THROW((dpf::eval_interval<0>(dpf0, from, to)));
|
||||
ASSERT_NO_THROW((dpf::eval_interval<0>(dpf1, from, to)));
|
||||
ASSERT_THROW((dpf::eval_interval<1>(dpf0, from, to)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_interval<1>(dpf1, from, to)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_interval<0, 1>(dpf0, from, to)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_interval<0, 1>(dpf1, from, to)), std::runtime_error);
|
||||
|
||||
ASSERT_NO_THROW((dpf::eval_full<0>(dpf0)));
|
||||
ASSERT_NO_THROW((dpf::eval_full<0>(dpf1)));
|
||||
ASSERT_THROW((dpf::eval_full<1>(dpf0)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_full<1>(dpf1)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_full<0, 1>(dpf0)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_full<0, 1>(dpf1)), std::runtime_error);
|
||||
|
||||
std::array<input_type, 16> points{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
ASSERT_NO_THROW((dpf::eval_sequence<0>(dpf0, std::begin(points), std::end(points))));
|
||||
ASSERT_NO_THROW((dpf::eval_sequence<0>(dpf1, std::begin(points), std::end(points))));
|
||||
ASSERT_THROW((dpf::eval_sequence<1>(dpf0, std::begin(points), std::end(points))), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_sequence<1>(dpf1, std::begin(points), std::end(points))), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_sequence<0, 1>(dpf0, std::begin(points), std::end(points))), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_sequence<0, 1>(dpf1, std::begin(points), std::end(points))), std::runtime_error);
|
||||
|
||||
auto recipe0 = dpf::make_sequence_recipe(dpf0, std::begin(points), std::end(points));
|
||||
auto recipe1 = dpf::make_sequence_recipe(dpf1, std::begin(points), std::end(points));
|
||||
ASSERT_NO_THROW((dpf::eval_sequence<0>(dpf0, recipe0)));
|
||||
ASSERT_NO_THROW((dpf::eval_sequence<0>(dpf1, recipe1)));
|
||||
ASSERT_THROW((dpf::eval_sequence<1>(dpf0, recipe0)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_sequence<1>(dpf1, recipe1)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_sequence<0, 1>(dpf0, recipe0)), std::runtime_error);
|
||||
ASSERT_THROW((dpf::eval_sequence<0, 1>(dpf1, recipe1)), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(WildcardTest, SingleLeafSuccess)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using concrete_type = uint32_t;
|
||||
using output_type = dpf::wildcard_value<concrete_type>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
|
||||
input_type x = 0xAA, from = 0x33, to = 0xCC;
|
||||
output_type y;
|
||||
concrete_type y_exp = 0xAAAAAAAA,
|
||||
y_shr0 = 0x12345678,
|
||||
y_shr1 = y_exp - y_shr0,
|
||||
zero_output = 0;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
|
||||
assign_leaf(dpf0, dpf1, y_shr0, y_shr1);
|
||||
|
||||
for (std::size_t i = std::numeric_limits<input_type>::min(); i <= std::numeric_limits<input_type>::max(); ++i)
|
||||
{
|
||||
auto y0 = *dpf::eval_point(dpf0, i);
|
||||
auto y1 = *dpf::eval_point(dpf1, i);
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(y0, y1), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(y0, y1), zero_output);
|
||||
}
|
||||
}
|
||||
|
||||
auto [bufint0, iterint0] = dpf::eval_interval(dpf0, from, to);
|
||||
auto [bufint1, iterint1] = dpf::eval_interval(dpf1, from, to);
|
||||
auto itint0 = std::begin(iterint0);
|
||||
auto itint1 = std::begin(iterint1);
|
||||
for (std::size_t i = from; i <= to; ++i, ++itint0, ++itint1)
|
||||
{
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itint0, *itint1), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itint0, *itint1), zero_output);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itint0, std::end(iterint0));
|
||||
ASSERT_EQ(itint1, std::end(iterint1));
|
||||
|
||||
auto [bufful0, iterful0] = dpf::eval_full(dpf0);
|
||||
auto [bufful1, iterful1] = dpf::eval_full(dpf1);
|
||||
auto itful0 = std::begin(iterful0);
|
||||
auto itful1 = std::begin(iterful1);
|
||||
for (std::size_t i = std::numeric_limits<input_type>::min(); i <= std::numeric_limits<input_type>::max(); ++i, ++itful0, ++itful1)
|
||||
{
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itful0, *itful1), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itful0, *itful1), zero_output);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itful0, std::end(iterful0));
|
||||
ASSERT_EQ(itful1, std::end(iterful1));
|
||||
|
||||
std::array<input_type, 16> points{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
auto [bufseq0, iterseq0] = dpf::eval_sequence(dpf0, std::begin(points), std::end(points));
|
||||
auto [bufseq1, iterseq1] = dpf::eval_sequence(dpf1, std::begin(points), std::end(points));
|
||||
auto itseq0 = std::begin(iterseq0);
|
||||
auto itseq1 = std::begin(iterseq1);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itseq0, ++itseq1)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itseq0, *itseq1), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itseq0, *itseq1), zero_output);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itseq0, std::end(iterseq0));
|
||||
ASSERT_EQ(itseq1, std::end(iterseq1));
|
||||
|
||||
auto [bufbre0, iterbre0] = dpf::eval_sequence_breadth_first(dpf0, std::begin(points), std::end(points));
|
||||
auto [bufbre1, iterbre1] = dpf::eval_sequence_breadth_first(dpf1, std::begin(points), std::end(points));
|
||||
auto itbre0 = std::begin(iterbre0);
|
||||
auto itbre1 = std::begin(iterbre1);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itbre0, ++itbre1)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itbre0, *itbre1), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itbre0, *itbre1), zero_output);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itbre0, std::end(iterbre0));
|
||||
ASSERT_EQ(itbre1, std::end(iterbre1));
|
||||
|
||||
auto recipe0 = dpf::make_sequence_recipe(dpf0, std::begin(points), std::end(points));
|
||||
auto recipe1 = dpf::make_sequence_recipe(dpf1, std::begin(points), std::end(points));
|
||||
auto [bufrec0, iterrec0] = dpf::eval_sequence(dpf0, recipe0);
|
||||
auto [bufrec1, iterrec1] = dpf::eval_sequence(dpf1, recipe1);
|
||||
auto itrec0 = std::begin(iterrec0);
|
||||
auto itrec1 = std::begin(iterrec1);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itrec0, ++itrec1)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itrec0, *itrec1), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itrec0, *itrec1), zero_output);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itrec0, std::end(iterrec0));
|
||||
ASSERT_EQ(itrec1, std::end(iterrec1));
|
||||
}
|
||||
|
||||
TEST(WildcardTest, MultiLeafSuccess)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using output_type0 = uint32_t;
|
||||
using concrete_type = uint32_t;
|
||||
using output_type1 = dpf::wildcard_value<concrete_type>;
|
||||
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type0, output_type1>;
|
||||
input_type x = 0xAA, from = 0x33, to = 0xCC;
|
||||
output_type0 y0 = 0x55555555,
|
||||
zero_output0 = 0;
|
||||
output_type1 y1;
|
||||
concrete_type y_exp = 0xAAAAAAAA,
|
||||
y_shr0 = 0x12345678,
|
||||
y_shr1 = y_exp - y_shr0,
|
||||
zero_output1 = 0;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y0, y1);
|
||||
|
||||
for (std::size_t i = std::numeric_limits<input_type>::min(); i <= std::numeric_limits<input_type>::max(); ++i)
|
||||
{
|
||||
auto ypoi0 = *dpf::eval_point<0>(dpf0, i);
|
||||
auto ypoi1 = *dpf::eval_point<0>(dpf1, i);
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(ypoi0, ypoi1), y0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(ypoi0, ypoi1), zero_output0);
|
||||
}
|
||||
}
|
||||
|
||||
auto [bufint00, iterint00] = dpf::eval_interval<0>(dpf0, from, to);
|
||||
auto [bufint01, iterint01] = dpf::eval_interval<0>(dpf1, from, to);
|
||||
auto itint00 = std::begin(iterint00);
|
||||
auto itint01 = std::begin(iterint01);
|
||||
for (std::size_t i = from; i <= to; ++i, ++itint00, ++itint01)
|
||||
{
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itint00, *itint01), y0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itint00, *itint01), zero_output0);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itint00, std::end(iterint00));
|
||||
ASSERT_EQ(itint01, std::end(iterint01));
|
||||
|
||||
auto [bufful00, iterful00] = dpf::eval_full<0>(dpf0);
|
||||
auto [bufful01, iterful01] = dpf::eval_full<0>(dpf1);
|
||||
auto itful00 = std::begin(iterful00);
|
||||
auto itful01 = std::begin(iterful01);
|
||||
for (std::size_t i = std::numeric_limits<input_type>::min(); i <= std::numeric_limits<input_type>::max(); ++i, ++itful00, ++itful01)
|
||||
{
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itful00, *itful01), y0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itful00, *itful01), zero_output0);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itful00, std::end(iterful00));
|
||||
ASSERT_EQ(itful01, std::end(iterful01));
|
||||
|
||||
std::array<input_type, 16> points{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
auto [bufseq00, iterseq00] = dpf::eval_sequence<0>(dpf0, std::begin(points), std::end(points));
|
||||
auto [bufseq01, iterseq01] = dpf::eval_sequence<0>(dpf1, std::begin(points), std::end(points));
|
||||
auto itseq00 = std::begin(iterseq00);
|
||||
auto itseq01 = std::begin(iterseq01);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itseq00, ++itseq01)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itseq00, *itseq01), y0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itseq00, *itseq01), zero_output0);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itseq00, std::end(iterseq00));
|
||||
ASSERT_EQ(itseq01, std::end(iterseq01));
|
||||
|
||||
auto [bufbre00, iterbre00] = dpf::eval_sequence_breadth_first<0>(dpf0, std::begin(points), std::end(points));
|
||||
auto [bufbre01, iterbre01] = dpf::eval_sequence_breadth_first<0>(dpf1, std::begin(points), std::end(points));
|
||||
auto itbre00 = std::begin(iterbre00);
|
||||
auto itbre01 = std::begin(iterbre01);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itbre00, ++itbre01)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itbre00, *itbre01), y0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itbre00, *itbre01), zero_output0);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itbre00, std::end(iterbre00));
|
||||
ASSERT_EQ(itbre01, std::end(iterbre01));
|
||||
|
||||
auto recipe0 = dpf::make_sequence_recipe(dpf0, std::begin(points), std::end(points));
|
||||
auto recipe1 = dpf::make_sequence_recipe(dpf1, std::begin(points), std::end(points));
|
||||
auto [bufrec00, iterrec00] = dpf::eval_sequence<0>(dpf0, recipe0);
|
||||
auto [bufrec01, iterrec01] = dpf::eval_sequence<0>(dpf1, recipe1);
|
||||
auto itrec00 = std::begin(iterrec00);
|
||||
auto itrec01 = std::begin(iterrec01);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itrec00, ++itrec01)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itrec00, *itrec01), y0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itrec00, *itrec01), zero_output0);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itrec00, std::end(iterrec00));
|
||||
ASSERT_EQ(itrec01, std::end(iterrec01));
|
||||
|
||||
assign_leaf<1>(dpf0, dpf1, y_shr0, y_shr1);
|
||||
|
||||
for (std::size_t i = std::numeric_limits<input_type>::min(); i <= std::numeric_limits<input_type>::max(); ++i)
|
||||
{
|
||||
auto ypoi0 = *dpf::eval_point<1>(dpf0, i);
|
||||
auto ypoi1 = *dpf::eval_point<1>(dpf1, i);
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(ypoi0, ypoi1), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(ypoi0, ypoi1), zero_output1);
|
||||
}
|
||||
}
|
||||
|
||||
auto [bufint10, iterint10] = dpf::eval_interval<1>(dpf0, from, to);
|
||||
auto [bufint11, iterint11] = dpf::eval_interval<1>(dpf1, from, to);
|
||||
auto itint10 = std::begin(iterint10);
|
||||
auto itint11 = std::begin(iterint11);
|
||||
for (std::size_t i = from; i <= to; ++i, ++itint10, ++itint11)
|
||||
{
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itint10, *itint11), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itint10, *itint11), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itint10, std::end(iterint10));
|
||||
ASSERT_EQ(itint11, std::end(iterint11));
|
||||
|
||||
auto [bufful10, iterful10] = dpf::eval_full<1>(dpf0);
|
||||
auto [bufful11, iterful11] = dpf::eval_full<1>(dpf1);
|
||||
auto itful10 = std::begin(iterful10);
|
||||
auto itful11 = std::begin(iterful11);
|
||||
for (std::size_t i = std::numeric_limits<input_type>::min(); i <= std::numeric_limits<input_type>::max(); ++i, ++itful10, ++itful11)
|
||||
{
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itful10, *itful11), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itful10, *itful11), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itful10, std::end(iterful10));
|
||||
ASSERT_EQ(itful11, std::end(iterful11));
|
||||
|
||||
auto [bufseq10, iterseq10] = dpf::eval_sequence<1>(dpf0, std::begin(points), std::end(points));
|
||||
auto [bufseq11, iterseq11] = dpf::eval_sequence<1>(dpf1, std::begin(points), std::end(points));
|
||||
auto itseq10 = std::begin(iterseq10);
|
||||
auto itseq11 = std::begin(iterseq11);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itseq10, ++itseq11)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itseq10, *itseq11), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itseq10, *itseq11), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itseq10, std::end(iterseq10));
|
||||
ASSERT_EQ(itseq11, std::end(iterseq11));
|
||||
|
||||
auto [bufbre10, iterbre10] = dpf::eval_sequence_breadth_first<1>(dpf0, std::begin(points), std::end(points));
|
||||
auto [bufbre11, iterbre11] = dpf::eval_sequence_breadth_first<1>(dpf1, std::begin(points), std::end(points));
|
||||
auto itbre10 = std::begin(iterbre10);
|
||||
auto itbre11 = std::begin(iterbre11);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itbre10, ++itbre11)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itbre10, *itbre11), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itbre10, *itbre11), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itbre10, std::end(iterbre10));
|
||||
ASSERT_EQ(itbre11, std::end(iterbre11));
|
||||
|
||||
auto [bufrec10, iterrec10] = dpf::eval_sequence<1>(dpf0, recipe0);
|
||||
auto [bufrec11, iterrec11] = dpf::eval_sequence<1>(dpf1, recipe1);
|
||||
auto itrec10 = std::begin(iterrec10);
|
||||
auto itrec11 = std::begin(iterrec11);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itrec10, ++itrec11)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itrec10, *itrec11), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(*itrec10, *itrec11), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itrec10, std::end(iterrec10));
|
||||
ASSERT_EQ(itrec11, std::end(iterrec11));
|
||||
|
||||
for (std::size_t i = std::numeric_limits<input_type>::min(); i <= std::numeric_limits<input_type>::max(); ++i)
|
||||
{
|
||||
auto ypoi0 = dpf::eval_point<0, 1>(dpf0, i);
|
||||
auto ypoi1 = dpf::eval_point<0, 1>(dpf1, i);
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(static_cast<output_type0>(dpf::reconstruct(std::get<0>(ypoi0), std::get<0>(ypoi1))), y0);
|
||||
ASSERT_EQ(static_cast<concrete_type>(dpf::reconstruct(std::get<1>(ypoi0), std::get<1>(ypoi1))), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(static_cast<output_type0>(dpf::reconstruct(std::get<0>(ypoi0), std::get<0>(ypoi1))), zero_output0);
|
||||
ASSERT_EQ(static_cast<concrete_type>(dpf::reconstruct(std::get<1>(ypoi0), std::get<1>(ypoi1))), zero_output1);
|
||||
}
|
||||
}
|
||||
|
||||
auto [bufintmul0, iterintmul0] = dpf::eval_interval<0, 1>(dpf0, from, to);
|
||||
auto [bufintmul1, iterintmul1] = dpf::eval_interval<0, 1>(dpf1, from, to);
|
||||
auto zipint0 = dpf::tuple_as_zip(iterintmul0);
|
||||
auto zipint1 = dpf::tuple_as_zip(iterintmul1);
|
||||
auto itintmul0 = std::begin(zipint0);
|
||||
auto itintmul1 = std::begin(zipint1);
|
||||
for (std::size_t i = from; i <= to; ++i, ++itintmul0, ++itintmul1)
|
||||
{
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<0>(*itintmul0), std::get<0>(*itintmul1)), y0);
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<1>(*itintmul0), std::get<1>(*itintmul1)), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<0>(*itintmul0), std::get<0>(*itintmul1)), zero_output0);
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<1>(*itintmul0), std::get<1>(*itintmul1)), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itintmul0, std::end(zipint0));
|
||||
ASSERT_EQ(itintmul1, std::end(zipint1));
|
||||
|
||||
auto [buffulmul0, iterfulmul0] = dpf::eval_full<0, 1>(dpf0);
|
||||
auto [buffulmul1, iterfulmul1] = dpf::eval_full<0, 1>(dpf1);
|
||||
auto zipful0 = dpf::tuple_as_zip(iterfulmul0);
|
||||
auto zipful1 = dpf::tuple_as_zip(iterfulmul1);
|
||||
auto itfulmul0 = std::begin(zipful0);
|
||||
auto itfulmul1 = std::begin(zipful1);
|
||||
for (std::size_t i = std::numeric_limits<input_type>::min(); i <= std::numeric_limits<input_type>::max(); ++i, ++itfulmul0, ++itfulmul1)
|
||||
{
|
||||
if (i == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<0>(*itfulmul0), std::get<0>(*itfulmul1)), y0);
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<1>(*itfulmul0), std::get<1>(*itfulmul1)), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<0>(*itfulmul0), std::get<0>(*itfulmul1)), zero_output0);
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<1>(*itfulmul0), std::get<1>(*itfulmul1)), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itfulmul0, std::end(zipful0));
|
||||
ASSERT_EQ(itfulmul1, std::end(zipful1));
|
||||
|
||||
auto [bufseqmul0, iterseqmul0] = dpf::eval_sequence<0, 1>(dpf0, std::begin(points), std::end(points));
|
||||
auto [bufseqmul1, iterseqmul1] = dpf::eval_sequence<0, 1>(dpf1, std::begin(points), std::end(points));
|
||||
auto zipseq0 = dpf::tuple_as_zip(iterseqmul0);
|
||||
auto zipseq1 = dpf::tuple_as_zip(iterseqmul1);
|
||||
auto itseqmul0 = std::begin(zipseq0);
|
||||
auto itseqmul1 = std::begin(zipseq1);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itseqmul0, ++itseqmul1)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<0>(*itseqmul0), std::get<0>(*itseqmul1)), y0);
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<1>(*itseqmul0), std::get<1>(*itseqmul1)), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<0>(*itseqmul0), std::get<0>(*itseqmul1)), zero_output0);
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<1>(*itseqmul0), std::get<1>(*itseqmul1)), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itseqmul0, std::end(zipseq0));
|
||||
ASSERT_EQ(itseqmul1, std::end(zipseq1));
|
||||
|
||||
auto [bufrecmul0, iterrecmul0] = dpf::eval_sequence<0, 1>(dpf0, recipe0);
|
||||
auto [bufrecmul1, iterrecmul1] = dpf::eval_sequence<0, 1>(dpf1, recipe1);
|
||||
auto ziprec0 = dpf::tuple_as_zip(iterrecmul0);
|
||||
auto ziprec1 = dpf::tuple_as_zip(iterrecmul1);
|
||||
auto itrecmul0 = std::begin(ziprec0);
|
||||
auto itrecmul1 = std::begin(ziprec1);
|
||||
for (std::size_t i = 0; i < points.size(); ++i, ++itrecmul0, ++itrecmul1)
|
||||
{
|
||||
if (points[i] == x)
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<0>(*itrecmul0), std::get<0>(*itrecmul1)), y0);
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<1>(*itrecmul0), std::get<1>(*itrecmul1)), y_exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<0>(*itrecmul0), std::get<0>(*itrecmul1)), zero_output0);
|
||||
ASSERT_EQ(dpf::reconstruct(std::get<1>(*itrecmul0), std::get<1>(*itrecmul1)), zero_output1);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(itrecmul0, std::end(ziprec0));
|
||||
ASSERT_EQ(itrecmul1, std::end(ziprec1));
|
||||
}
|
||||
|
||||
TEST(WildcardTest, PackedSmallWildcardsAtNonTerminalAssignAll)
|
||||
{
|
||||
// Four packed uint8 wildcards at a non-terminal prefix, plus a concrete
|
||||
// deepest output. Assign every wildcard leaf through the asio path.
|
||||
using concrete_t = uint8_t;
|
||||
dpf::wildcard_value<concrete_t> w;
|
||||
uint16_t x = 0x55aa;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x,
|
||||
dpf::at<10>(w, w, w, w),
|
||||
uint16_t{99});
|
||||
|
||||
ASSERT_THROW((void)dpf::eval_point(dpf::out<0, 10>, dpf0, x), std::runtime_error);
|
||||
ASSERT_EQ(static_cast<uint16_t>(
|
||||
dpf::reconstruct(*dpf::eval_point(dpf::out<4>, dpf0, x), *dpf::eval_point(dpf::out<4>, dpf1, x))),
|
||||
uint16_t{99});
|
||||
|
||||
const concrete_t want[4] = {1, 2, 3, 4};
|
||||
const concrete_t shr0[4] = {10, 20, 30, 40};
|
||||
assign_leaf<0>(dpf0, dpf1, shr0[0], static_cast<concrete_t>(want[0] - shr0[0]));
|
||||
assign_leaf<1>(dpf0, dpf1, shr0[1], static_cast<concrete_t>(want[1] - shr0[1]));
|
||||
assign_leaf<2>(dpf0, dpf1, shr0[2], static_cast<concrete_t>(want[2] - shr0[2]));
|
||||
assign_leaf<3>(dpf0, dpf1, shr0[3], static_cast<concrete_t>(want[3] - shr0[3]));
|
||||
|
||||
ASSERT_EQ(static_cast<concrete_t>(
|
||||
dpf::reconstruct(*dpf::eval_point(dpf::out<0, 10>, dpf0, x), *dpf::eval_point(dpf::out<0, 10>, dpf1, x))),
|
||||
want[0]);
|
||||
ASSERT_EQ(static_cast<concrete_t>(
|
||||
dpf::reconstruct(*dpf::eval_point(dpf::out<3, 10>, dpf0, x), *dpf::eval_point(dpf::out<3, 10>, dpf1, x))),
|
||||
want[3]);
|
||||
ASSERT_EQ(static_cast<concrete_t>(
|
||||
dpf::reconstruct(
|
||||
*dpf::eval_point(dpf::out<0, 10>, dpf0,
|
||||
static_cast<uint16_t>(x ^ (1u << 6))),
|
||||
*dpf::eval_point(dpf::out<0, 10>, dpf1,
|
||||
static_cast<uint16_t>(x ^ (1u << 6))))),
|
||||
concrete_t{0});
|
||||
}
|
||||
166
test/tests/window_lut_test.cpp
Normal file
166
test/tests/window_lut_test.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "grotto/window_lut.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct sample
|
||||
{
|
||||
int which;
|
||||
unsigned k;
|
||||
std::int64_t raw;
|
||||
std::int64_t y;
|
||||
};
|
||||
|
||||
const sample kExact[] = {
|
||||
#include "window_samples.inc"
|
||||
};
|
||||
|
||||
const sample kTruth[] = {
|
||||
#include "window_accuracy.inc"
|
||||
};
|
||||
|
||||
long double sigmoid(long double x) { return 1.0L / (1.0L + expl(-x)); }
|
||||
|
||||
long double softplus(long double x)
|
||||
{
|
||||
if (x > 40.0L)
|
||||
return x;
|
||||
if (x < -40.0L)
|
||||
return expl(x);
|
||||
return log1pl(expl(x));
|
||||
}
|
||||
|
||||
long double reference(grotto::window which, unsigned k, long double x)
|
||||
{
|
||||
switch (which)
|
||||
{
|
||||
case grotto::window::smoothstep:
|
||||
if (x <= -0.5L)
|
||||
return 0;
|
||||
if (x >= 0.5L)
|
||||
return 1;
|
||||
return -2.0L * x * x * x + 1.5L * x + 0.5L;
|
||||
case grotto::window::sigmoid:
|
||||
return sigmoid(x);
|
||||
case grotto::window::tanh:
|
||||
return tanhl(x);
|
||||
case grotto::window::erf:
|
||||
return erfl(x);
|
||||
case grotto::window::erfc:
|
||||
return erfcl(x);
|
||||
case grotto::window::softplus:
|
||||
return softplus(x);
|
||||
case grotto::window::softminus:
|
||||
return x - softplus(x);
|
||||
case grotto::window::logsigmoid:
|
||||
return -softplus(-x);
|
||||
case grotto::window::gelu:
|
||||
return x * (1.0L + erfl(x / sqrtl(2.0L))) / 2.0L;
|
||||
case grotto::window::silu:
|
||||
return x * sigmoid(x);
|
||||
case grotto::window::mish:
|
||||
return x * tanhl(softplus(x));
|
||||
case grotto::window::elish:
|
||||
return x < 0 ? expm1l(x) * sigmoid(x) : x * sigmoid(x);
|
||||
case grotto::window::serf:
|
||||
return x * erfl(softplus(x));
|
||||
case grotto::window::tanhexp:
|
||||
return x * tanhl(expl(x));
|
||||
case grotto::window::asin:
|
||||
return asinl(x);
|
||||
case grotto::window::acos:
|
||||
return acosl(x);
|
||||
case grotto::window::probit:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void expect_close(grotto::window which, unsigned k, std::int64_t raw)
|
||||
{
|
||||
const auto y = grotto::eval_window(which, k, raw);
|
||||
const long double x = ldexpl(static_cast<long double>(raw), -static_cast<int>(k));
|
||||
const long double truth = reference(which, k, x) * ldexpl(1.0L, static_cast<int>(k));
|
||||
EXPECT_LE(fabsl(static_cast<long double>(y) - truth), 1.5L)
|
||||
<< static_cast<int>(which) << " k=" << k << " raw=" << raw << " y=" << y;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(WindowLut, HornerMatchesGeneratedSamples)
|
||||
{
|
||||
for (const sample & point : kExact)
|
||||
{
|
||||
EXPECT_EQ(grotto::eval_window(static_cast<grotto::window>(point.which), point.k, point.raw), point.y)
|
||||
<< point.which << " k=" << point.k << " raw=" << point.raw;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WindowLut, WithinOneUlpOfLibm)
|
||||
{
|
||||
for (const sample & point : kTruth)
|
||||
{
|
||||
if (point.which == static_cast<int>(grotto::window::probit))
|
||||
continue;
|
||||
expect_close(static_cast<grotto::window>(point.which), point.k, point.raw);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WindowLut, ProbitMatchesMpmathRounding)
|
||||
{
|
||||
for (const sample & point : kTruth)
|
||||
{
|
||||
if (point.which != static_cast<int>(grotto::window::probit))
|
||||
continue;
|
||||
const auto y = grotto::eval_window(grotto::window::probit, point.k, point.raw);
|
||||
EXPECT_LE(std::llabs(y - point.y), 1) << "k=" << point.k << " raw=" << point.raw;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WindowLut, SmoothstepKnotsAreExact)
|
||||
{
|
||||
EXPECT_EQ(grotto::eval_window(grotto::window::smoothstep, 8, -128), 0);
|
||||
EXPECT_EQ(grotto::eval_window(grotto::window::smoothstep, 8, 128), 256);
|
||||
EXPECT_EQ(grotto::eval_window(grotto::window::smoothstep, 8, 0), 128);
|
||||
EXPECT_EQ(grotto::eval_window(grotto::window::smoothstep, 16, -100000), 0);
|
||||
EXPECT_EQ(grotto::eval_window(grotto::window::smoothstep, 16, 100000), 1 << 16);
|
||||
}
|
||||
|
||||
TEST(WindowLut, ExhaustiveLowPrecision)
|
||||
{
|
||||
for (int which_i = 0; which_i <= static_cast<int>(grotto::window::tanhexp); ++which_i)
|
||||
{
|
||||
if (which_i == static_cast<int>(grotto::window::probit))
|
||||
continue;
|
||||
const auto which = static_cast<grotto::window>(which_i);
|
||||
for (unsigned k : {8u, 12u})
|
||||
{
|
||||
const std::int64_t span = std::int64_t{30} << k;
|
||||
const std::int64_t step = k == 8 ? 1 : 17;
|
||||
for (std::int64_t raw = -span; raw <= span; raw += step)
|
||||
expect_close(which, k, raw);
|
||||
}
|
||||
}
|
||||
for (unsigned k : {8u, 12u})
|
||||
{
|
||||
const auto one = std::int64_t{1} << k;
|
||||
for (std::int64_t raw = -one; raw <= one; raw += (k == 8 ? 1 : 8))
|
||||
{
|
||||
expect_close(grotto::window::asin, k, raw);
|
||||
expect_close(grotto::window::acos, k, raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WindowLut, RejectsBadDomain)
|
||||
{
|
||||
EXPECT_THROW(grotto::eval_window(grotto::window::sigmoid, 7, 0), std::invalid_argument);
|
||||
EXPECT_THROW(grotto::eval_window(grotto::window::asin, 8, 257), std::out_of_range);
|
||||
EXPECT_THROW(grotto::eval_window(grotto::window::probit, 8, 0), std::out_of_range);
|
||||
EXPECT_THROW(grotto::eval_window(grotto::window::probit, 8, 256), std::out_of_range);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue