7#ifndef _MINISKETCH_SKETCH_IMPL_H_
8#define _MINISKETCH_SKETCH_IMPL_H_
18void PolyMod(
const std::vector<typename F::Elem>& mod, std::vector<typename F::Elem>& val,
const F& field) {
19 size_t modsize = mod.size();
21 if (val.size() < modsize)
return;
23 while (val.size() >= modsize) {
24 auto term = val.back();
27 typename F::Multiplier mul(field, term);
28 for (
size_t x = 0; x < mod.size() - 1; ++x) {
29 val[val.size() - modsize + 1 + x] ^= mul(mod[x]);
33 while (val.size() > 0 && val.back() == 0) val.pop_back();
38void DivMod(
const std::vector<typename F::Elem>& mod, std::vector<typename F::Elem>& val, std::vector<typename F::Elem>& div,
const F& field) {
39 size_t modsize = mod.size();
41 if (val.size() < mod.size()) {
46 div.resize(val.size() - mod.size() + 1);
47 while (val.size() >= modsize) {
48 auto term = val.back();
49 div[val.size() - modsize] = term;
52 typename F::Multiplier mul(field, term);
53 for (
size_t x = 0; x < mod.size() - 1; ++x) {
54 val[val.size() - modsize + 1 + x] ^= mul(mod[x]);
62typename F::Elem
MakeMonic(std::vector<typename F::Elem>& a,
const F& field) {
64 if (a.back() == 1)
return 0;
65 auto inv = field.Inv(a.back());
66 typename F::Multiplier mul(field, inv);
68 for (
size_t i = 0; i < a.size() - 1; ++i) {
76void GCD(std::vector<typename F::Elem>& a, std::vector<typename F::Elem>& b,
const F& field) {
77 if (a.size() < b.size()) std::swap(a, b);
78 while (b.size() > 0) {
92void Sqr(std::vector<typename F::Elem>& poly,
const F& field) {
93 if (poly.size() == 0)
return;
94 poly.resize(poly.size() * 2 - 1);
95 for (
size_t i = 0; i < poly.size(); ++i) {
96 auto x = poly.size() - i - 1;
97 poly[x] = (x & 1) ? 0 : field.Sqr(poly[x / 2]);
103void TraceMod(
const std::vector<typename F::Elem>& mod, std::vector<typename F::Elem>&
out,
const typename F::Elem& param,
const F& field) {
104 out.reserve(mod.size() * 2);
109 for (
int i = 0; i < field.Bits() - 1; ++i) {
111 if (
out.size() < 2)
out.resize(2);
129bool RecFindRoots(std::vector<std::vector<typename F::Elem>>& stack,
size_t pos, std::vector<typename F::Elem>& roots,
bool fully_factorizable,
int depth,
typename F::Elem randv,
const F& field) {
130 auto& ppoly = stack[pos];
135 CHECK_SAFE(ppoly.size() > 1 && ppoly.back() == 1);
137 if (ppoly.size() == 2) {
138 roots.push_back(ppoly[0]);
142 if (ppoly.size() == 3) {
144 auto input = field.Mul(ppoly[0], field.Sqr(field.Inv(ppoly[1])));
145 auto root = field.Qrt(input);
146 if ((field.Sqr(root) ^ root) != input) {
150 auto sol = field.Mul(root, ppoly[1]);
151 roots.push_back(sol);
152 roots.push_back(sol ^ ppoly[1]);
156 if (pos + 3 > stack.size()) {
158 stack.resize((pos + 3) * 2);
160 auto& poly = stack[pos];
161 auto& tmp = stack[pos + 1];
162 auto& trace = stack[pos + 2];
165 for (
int iter = 0;; ++iter) {
168 TraceMod(poly, trace, randv, field);
170 if (iter >= 1 && !fully_factorizable) {
206 for (
size_t i = 0; i < trace.size(); ++i) {
209 while (tmp.size() && tmp.back() == 0) tmp.pop_back();
216 if (tmp.size() != 0)
return false;
217 fully_factorizable =
true;
220 if (fully_factorizable) {
225 CHECK_RETURN(field.Bits() - depth >= std::numeric_limits<
decltype(poly.size())>::digits ||
226 (poly.size() - 2) >> (field.Bits() - depth) == 0,
false);
232 randv = field.Mul2(randv);
234 GCD(trace, tmp, field);
235 if (trace.size() != poly.size() && trace.size() > 1)
break;
238 DivMod(trace, poly, tmp, field);
242 std::swap(poly, trace);
245 if (!
RecFindRoots(stack, pos + 1, roots, fully_factorizable, depth, randv, field))
return false;
264std::vector<typename F::Elem>
FindRoots(
const std::vector<typename F::Elem>& poly,
typename F::Elem basis,
const F& field) {
265 std::vector<typename F::Elem> roots;
268 if (poly.size() == 1)
return roots;
269 roots.reserve(poly.size() - 1);
270 std::vector<std::vector<typename F::Elem>> stack = {poly};
273 if (!
RecFindRoots(stack, 0, roots,
false, 0, basis, field)) {
282std::vector<typename F::Elem>
BerlekampMassey(
const std::vector<typename F::Elem>& syndromes,
size_t max_degree,
const F& field) {
283 std::vector<typename F::Multiplier> table;
284 std::vector<typename F::Elem> current, prev, tmp;
285 current.reserve(syndromes.size() / 2 + 1);
286 prev.reserve(syndromes.size() / 2 + 1);
287 tmp.reserve(syndromes.size() / 2 + 1);
292 typename F::Elem b = 1, b_inv = 1;
293 bool b_have_inv =
true;
294 table.reserve(syndromes.size());
296 for (
size_t n = 0; n != syndromes.size(); ++n) {
297 table.emplace_back(field, syndromes[n]);
298 auto discrepancy = syndromes[n];
299 for (
size_t i = 1; i < current.size(); ++i) discrepancy ^= table[n - i](current[i]);
300 if (discrepancy != 0) {
301 int x =
static_cast<int>(n + 1 - (current.size() - 1) - (prev.size() - 1));
303 b_inv = field.Inv(b);
306 bool swap = 2 * (current.size() - 1) <= n;
308 if (prev.size() + x - 1 > max_degree)
return {};
310 current.resize(prev.size() + x);
312 typename F::Multiplier mul(field, field.Mul(discrepancy, b_inv));
313 for (
size_t i = 0; i < prev.size(); ++i) current[i + x] ^= mul(prev[i]);
315 std::swap(prev, tmp);
321 CHECK_RETURN(current.size() && current.back() != 0, {});
327 std::vector<typename F::Elem> all_syndromes;
328 all_syndromes.resize(odd_syndromes.size() * 2);
329 for (
size_t i = 0; i < odd_syndromes.size(); ++i) {
330 all_syndromes[i * 2] = odd_syndromes[i];
331 all_syndromes[i * 2 + 1] = field.Sqr(all_syndromes[i]);
333 return all_syndromes;
338 auto sqr = field.Sqr(
data);
339 typename F::Multiplier mul(field, sqr);
340 for (
auto& osyndrome : osyndromes) {
347std::vector<typename F::Elem>
FullDecode(
const std::vector<typename F::Elem>& osyndromes,
const F& field) {
348 auto asyndromes = ReconstructAllSyndromes<typename F::Elem>(osyndromes, field);
350 std::reverse(poly.begin(), poly.end());
362 template<
typename... Args>
364 std::random_device rng;
365 std::uniform_int_distribution<uint64_t> dist;
372 void Add(uint64_t val)
override
374 auto elem =
m_field.FromUint64(val);
382 m_field.Serialize(writer, val);
391 val =
m_field.Deserialize(reader);
399 if (poly.size() == 0)
return -1;
400 if (poly.size() == 1)
return 0;
401 if ((
int)poly.size() > 1 + max_count)
return -1;
402 std::reverse(poly.begin(), poly.end());
404 if (roots.size() == 0)
return -1;
406 for (
const auto& root : roots) {
409 return static_cast<int>(roots.size());
426 if (seed == (uint64_t)-1) {
Abstract class for internal representation of a minisketch object.
SketchImpl(int implementation, int bits, const Args &... args)
void Serialize(unsigned char *ptr) const override
size_t Merge(const Sketch *other_sketch) override
int Decode(int max_count, uint64_t *out) const override
void Add(uint64_t val) override
void Init(size_t count) override
void Deserialize(const unsigned char *ptr) override
size_t Syndromes() const override
std::vector< typename F::Elem > m_syndromes
void SetSeed(uint64_t seed) override
#define CHECK_RETURN(cond, rvar)
Check a condition and return on failure in non-verify builds, crash in verify builds.
#define CHECK_SAFE(cond)
Check macro that does nothing in normal non-verify builds but crashes in verify builds.
void AddToOddSyndromes(std::vector< typename F::Elem > &osyndromes, typename F::Elem data, const F &field)
bool RecFindRoots(std::vector< std::vector< typename F::Elem > > &stack, size_t pos, std::vector< typename F::Elem > &roots, bool fully_factorizable, int depth, typename F::Elem randv, const F &field)
One step of the root finding algorithm; finds roots of stack[pos] and adds them to roots.
void TraceMod(const std::vector< typename F::Elem > &mod, std::vector< typename F::Elem > &out, const typename F::Elem ¶m, const F &field)
Compute the trace map of (param*x) modulo mod, putting the result in out.
void PolyMod(const std::vector< typename F::Elem > &mod, std::vector< typename F::Elem > &val, const F &field)
Compute the remainder of a polynomial division of val by mod, putting the result in mod.
void GCD(std::vector< typename F::Elem > &a, std::vector< typename F::Elem > &b, const F &field)
Compute the GCD of two polynomials, putting the result in a.
std::vector< typename F::Elem > BerlekampMassey(const std::vector< typename F::Elem > &syndromes, size_t max_degree, const F &field)
F::Elem MakeMonic(std::vector< typename F::Elem > &a, const F &field)
Make a polynomial monic.
std::vector< typename F::Elem > FindRoots(const std::vector< typename F::Elem > &poly, typename F::Elem basis, const F &field)
Returns the roots of a fully factorizable polynomial.
void Sqr(std::vector< typename F::Elem > &poly, const F &field)
Square a polynomial.
void DivMod(const std::vector< typename F::Elem > &mod, std::vector< typename F::Elem > &val, std::vector< typename F::Elem > &div, const F &field)
Compute the quotient of a polynomial division of val by mod, putting the quotient in div and the rema...
std::vector< typename F::Elem > FullDecode(const std::vector< typename F::Elem > &osyndromes, const F &field)
std::vector< typename F::Elem > ReconstructAllSyndromes(const std::vector< typename F::Elem > &odd_syndromes, const F &field)