Record Grotto half-ulp tables and comparison geneval, and factor shared beaver terms before the quotient.
Horner and window evaluation need those tables in the tree. Comparison geneval opens the same value words as a Doerner–Shelat key. A factor common to every polynomial term is multiplied first so that preprocessing stays smaller. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3f10e05176
commit
875f09fec1
14 changed files with 42668 additions and 184 deletions
|
|
@ -1121,3 +1121,105 @@ TEST(Geneval, SignedRegressionsFromTheCornerPass)
|
|||
expect_prefix_words(wild.first, g.correction_words, g.correction_advice,
|
||||
g.live_levels, g.leaf_live, &g.leaf, sizeof(g.leaf));
|
||||
}
|
||||
|
||||
TEST(Geneval, CmpEmptyRangeOpensNothing)
|
||||
{
|
||||
reset_roots();
|
||||
const uint8_t ends[] = {0};
|
||||
auto g = dpf::geneval_cmp(uint8_t{1}, uint8_t{2}, ends, ends, rng<uint8_t>(),
|
||||
uint64_t{1});
|
||||
EXPECT_TRUE(g.party0.empty());
|
||||
EXPECT_TRUE(g.party1.empty());
|
||||
EXPECT_EQ(g.live_levels, 0u);
|
||||
EXPECT_TRUE(g.value_cw.empty());
|
||||
}
|
||||
|
||||
TEST(Geneval, CmpMatchesDoernerShelatKeyAndGtPredicate)
|
||||
{
|
||||
using in_t = uint8_t;
|
||||
const in_t alpha = 40;
|
||||
const in_t x0 = 0x11;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const uint64_t beta = 7;
|
||||
const std::vector<in_t> ends{0, 1, 10, 40, 200, 255, 40};
|
||||
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf_doerner_shelat(x0, x1, rng<in_t>(), dpf::gt(beta));
|
||||
reset_roots();
|
||||
auto g = dpf::geneval_cmp(x0, x1, ends.begin(), ends.end(), rng<in_t>(), beta);
|
||||
|
||||
using key_t = std::decay_t<decltype(keys.first)>;
|
||||
EXPECT_EQ(g.live_levels, key_t::depth);
|
||||
ASSERT_EQ(g.correction_words.size(), key_t::depth);
|
||||
ASSERT_EQ(g.value_cw.size(), key_t::depth);
|
||||
for (std::size_t level = 0; level < key_t::depth; ++level)
|
||||
{
|
||||
EXPECT_EQ(std::memcmp(&g.correction_words[level],
|
||||
&keys.first.correction_word(level), sizeof(simde__m128i)), 0) << level;
|
||||
EXPECT_EQ(g.correction_advice[level], keys.first.correction_advice(level)) << level;
|
||||
EXPECT_EQ(g.value_cw[level], keys.first.value_cw(level)) << level;
|
||||
}
|
||||
EXPECT_EQ(g.cw_last, keys.first.cw_last());
|
||||
EXPECT_EQ(g.addend0, keys.first.cmp_addend().raw());
|
||||
EXPECT_EQ(g.addend1, keys.second.cmp_addend().raw());
|
||||
EXPECT_EQ((g.addend0 + g.addend1) & g.mask, beta);
|
||||
ASSERT_EQ(g.party0.size(), ends.size());
|
||||
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const auto e0 = dpf::eval_point(dpf::cmp, keys.first, ends[i]);
|
||||
const auto e1 = dpf::eval_point(dpf::cmp, keys.second, ends[i]);
|
||||
EXPECT_EQ(g.party0[i], e0.raw()) << int(ends[i]);
|
||||
EXPECT_EQ(g.party1[i], e1.raw()) << int(ends[i]);
|
||||
const uint64_t opened = (g.party0[i] + g.party1[i]) & g.mask;
|
||||
EXPECT_EQ(opened, ends[i] > alpha ? beta : 0u) << int(ends[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Geneval, CmpSignedPayloadAndDomainMax)
|
||||
{
|
||||
using in_t = int16_t;
|
||||
const in_t alpha = -3;
|
||||
const in_t x0 = 9;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const uint64_t beta = 5;
|
||||
const std::vector<in_t> ends{-100, -3, -2, 0, 4, 32767};
|
||||
|
||||
reset_roots();
|
||||
auto g = dpf::geneval_cmp(x0, x1, ends.begin(), ends.end(), rng<in_t>(),
|
||||
dpf::gt(beta));
|
||||
EXPECT_EQ(g.live_levels, 16u);
|
||||
EXPECT_EQ(g.value_cw.size(), g.live_levels);
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const uint64_t opened = (g.party0[i] + g.party1[i]) & g.mask;
|
||||
EXPECT_EQ(opened, ends[i] > alpha ? beta : 0u) << ends[i];
|
||||
}
|
||||
|
||||
const in_t top0 = 1;
|
||||
const in_t top = std::numeric_limits<in_t>::max();
|
||||
const in_t top1 = static_cast<in_t>(top ^ top0);
|
||||
const std::vector<in_t> all{std::numeric_limits<in_t>::min(), in_t{0}, top};
|
||||
reset_roots();
|
||||
auto trivial = dpf::geneval_cmp(top0, top1, all.begin(), all.end(), rng<in_t>(),
|
||||
uint64_t{1});
|
||||
for (std::size_t i = 0; i < all.size(); ++i)
|
||||
EXPECT_EQ((trivial.party0[i] + trivial.party1[i]) & trivial.mask, 0u) << all[i];
|
||||
}
|
||||
|
||||
TEST(Geneval, CmpLtIsTheComplementOfTheStrictUpperSet)
|
||||
{
|
||||
using in_t = uint8_t;
|
||||
const in_t alpha = 10;
|
||||
const in_t x0 = 3;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const std::vector<in_t> ends{0, 10, 11, 255};
|
||||
reset_roots();
|
||||
auto g = dpf::geneval_cmp(x0, x1, ends.begin(), ends.end(), rng<in_t>(),
|
||||
dpf::lt(uint64_t{4}));
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
const uint64_t opened = (g.party0[i] + g.party1[i]) & g.mask;
|
||||
EXPECT_EQ(opened, ends[i] < alpha ? 4u : 0u) << int(ends[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue