53using Clock = std::chrono::steady_clock;
66 bool validate =
false;
68 size_t repetitions = 128;
71 unsigned seed = 20260317u;
78 double median_us = 0.0;
81 double stddev_us = 0.0;
86 std::string case_name;
88 size_t repetitions = 0;
96 std::stringstream
ss(
csv);
99 while (std::getline(
ss, token,
','))
103 sizes.
append(
static_cast<size_t>(std::stoull(token)));
114 for (
int i = 1; i <
argc; ++i)
116 const std::string
arg =
argv[i];
117 if (
arg ==
"--validate")
119 else if (
arg ==
"--json")
121 else if (
arg ==
"--repetitions" and i + 1 <
argc)
122 options.repetitions =
static_cast<size_t>(std::stoull(
argv[++i]));
124 options.warmup =
static_cast<size_t>(std::stoull(
argv[++i]));
126 options.samples =
static_cast<size_t>(std::stoull(
argv[++i]));
128 options.seed =
static_cast<unsigned>(std::stoul(
argv[++i]));
131 else if (
arg ==
"--help")
134 <<
"Usage: polynomial_benchmark [--validate] [--json]"
135 <<
" [--repetitions N] [--warmup N] [--samples N]"
136 <<
" [--seed N] [--sizes a,b,c]\n";
141 std::cerr <<
"Unknown option: " <<
arg <<
"\n";
148 std::cerr <<
"Repetitions, warmup, and samples must be positive\n";
154 std::cerr <<
"At least one benchmark size is required\n";
165 x +=
static_cast<uint64_t>(
slot + 1) * 0xC2B2AE3D27D4EB4FULL;
167 x *= 0xFF51AFD7ED558CCDULL;
169 long long value =
static_cast<long long>(x % 17ULL) - 8LL;
175 template <
typename Poly>
179 using Coeff =
typename Poly::Coeff;
180 Coeff result = Coeff{};
181 p.for_each_term([&result, &x](
size_t exp,
const Coeff &
coeff)
194 std::max<size_t>(1, degree / 7 + 1),
195 std::max<size_t>(2, degree / 3 + 1),
196 std::max<size_t>(3, (2 * degree) / 3 + 1),
200 for (
size_t i = 0; i < exponents.
size(); ++i)
201 p.set_coeff(exponents(i),
213 std::max<size_t>(1, degree / 5 + 1),
214 std::max<size_t>(2, degree / 2 + 1),
218 for (
size_t i = 0; i < exponents.
size(); ++i)
224 template <
typename MultiPoly>
233 Array<size_t>{std::max<size_t>(1, degree / 2), std::max<size_t>(1, degree / 3)},
234 Array<size_t>{std::max<size_t>(1, degree / 3), std::max<size_t>(1, degree / 2)},
239 for (
size_t i = 0; i < exponents.
size(); ++i)
240 p.add_to_coeff(exponents(i),
241 typename MultiPoly::Coeff(
250 auto x = LexMultiPoly::variable(3, 0);
251 auto y = LexMultiPoly::variable(3, 1);
252 auto z = LexMultiPoly::variable(3, 2);
270 gens.append(x *
y - z);
276 template <
typename Fn>
283 for (
size_t sample = 0; sample <
options.samples; ++sample)
289 const auto start = Clock::now();
292 const auto end = Clock::now();
295 std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(end - start).
count();
299 std::sort(&samples[0], &samples[0] + samples.
size());
302 stats.min_us = samples(0);
303 stats.max_us = samples(samples.
size() - 1);
304 stats.median_us = samples(samples.
size() / 2);
306 std::accumulate(&samples[0], &samples[0] + samples.
size(), 0.0) /
static_cast<double>(samples.
size());
309 for (
size_t i = 0; i < samples.
size(); ++i)
311 const double diff = samples(i) - stats.mean_us;
315 stats.stddev_us = std::sqrt(
variance);
324 for (
size_t i = 0; i <
options.sizes.size(); ++i)
326 const size_t degree =
options.sizes(i);
330 const double x = 0.875;
334 std::cerr <<
"[validate] univariate eval mismatch at size " << degree <<
"\n";
342 std::cerr <<
"[validate] univariate compose mismatch at size " << degree <<
"\n";
352 std::cerr <<
"[validate] univariate divmod identity mismatch at size " << degree <<
"\n";
365 std::cerr <<
"[validate] multivariate divmod identity mismatch at size " << degree <<
"\n";
370 for (
size_t g = 0; g <
gb.size(); ++g)
373 for (
size_t h = 0;
h <
gb.size(); ++
h)
380 std::cerr <<
"[validate] reduced Groebner basis not autoreduced at size "
396 for (
size_t i = 0; i <
options.sizes.size(); ++i)
403 row.case_name =
"uni_eval_sparse";
405 row.repetitions =
options.repetitions;
410 rows.
append(std::move(row));
417 row.case_name =
"uni_mul_sparse";
419 row.repetitions =
options.repetitions;
423 benchmark_sink +=
static_cast<long double>(c.degree() + c.num_terms());
425 rows.
append(std::move(row));
432 row.case_name =
"uni_compose_sparse";
434 row.repetitions =
options.repetitions;
438 benchmark_sink +=
static_cast<long double>(c.degree() + c.num_terms());
440 rows.
append(std::move(row));
448 row.case_name =
"uni_divmod_sparse_exact";
450 row.repetitions =
options.repetitions;
456 rows.
append(std::move(row));
464 row.case_name =
"multi_mul_sparse";
466 row.repetitions =
options.repetitions;
470 benchmark_sink +=
static_cast<long double>(c.degree() + c.num_terms());
472 rows.
append(std::move(row));
482 row.case_name =
"multi_divmod_exact";
484 row.repetitions =
options.repetitions;
488 benchmark_sink +=
static_cast<long double>(q(0).degree() +
r.degree());
490 rows.
append(std::move(row));
496 row.case_name =
"multi_groebner_reduced_lex";
498 row.repetitions = std::max<size_t>(1,
options.repetitions / 8);
506 rows.
append(std::move(row));
517 <<
" \"mode\": \"benchmark\",\n"
518 <<
" \"metadata\": {\n"
519 <<
" \"seed\": " <<
options.seed <<
",\n"
520 <<
" \"repetitions\": " <<
options.repetitions <<
",\n"
521 <<
" \"warmup\": " <<
options.warmup <<
",\n"
522 <<
" \"samples\": " <<
options.samples <<
"\n"
526 for (
size_t i = 0; i < rows.
size(); ++i)
528 const BenchmarkRow &row = rows(i);
530 <<
" \"case\": \"" << row.case_name <<
"\",\n"
531 <<
" \"size\": " << row.size <<
",\n"
532 <<
" \"repetitions\": " << row.repetitions <<
",\n"
533 <<
" \"mean_us\": " << std::setprecision(12) << row.stats.mean_us <<
",\n"
534 <<
" \"median_us\": " << row.stats.median_us <<
",\n"
535 <<
" \"min_us\": " << row.stats.min_us <<
",\n"
536 <<
" \"max_us\": " << row.stats.max_us <<
",\n"
537 <<
" \"stddev_us\": " << row.stats.stddev_us <<
"\n"
538 <<
" }" << (i + 1 == rows.
size() ?
"\n" :
",\n");
548 std::cout <<
"Polynomial benchmark (microseconds per call)\n"
549 << std::left << std::setw(28) <<
"case"
550 << std::setw(8) <<
"size"
551 << std::setw(12) <<
"median"
552 << std::setw(12) <<
"mean"
553 << std::setw(12) <<
"min"
554 << std::setw(12) <<
"max"
557 for (
size_t i = 0; i < rows.
size(); ++i)
559 const BenchmarkRow &row = rows(i);
560 std::cout << std::left << std::setw(28) << row.case_name
561 << std::setw(8) << row.size
562 << std::setw(12) << std::fixed << std::setprecision(3) << row.stats.median_us
563 << std::setw(12) << row.stats.mean_us
564 << std::setw(12) << row.stats.min_us
565 << std::setw(12) << row.stats.max_us
566 << row.stats.stddev_us <<
"\n";
569 std::cout <<
"Benchmark sink: " <<
static_cast<long double>(
benchmark_sink) <<
"\n";
586 std::cout <<
"polynomial_benchmark: validation passed\n";
597 catch (
const std::exception &e)
599 std::cerr <<
"polynomial_benchmark: " << e.what() <<
"\n";
Simple dynamic array with automatic resizing and functional operations.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Sparse multivariate polynomial.
Univariate polynomial over a generic coefficient ring.
std::pair< Gen_Polynomial, Gen_Polynomial > divmod(const Gen_Polynomial &d) const
Polynomial long division: returns (quotient, remainder).
void set_coeff(size_t exp, const Coefficient &c)
Set coefficient at exponent; removes entry if zero.
std::chrono::steady_clock Clock
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_exp_function > > exp(const __gmp_expr< T, U > &expr)
C power(C base, size_t exp)
Fast exponentiation by squaring.
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
size_t size(Node *root) noexcept
auto variance(const Container &data, bool population=false) -> std::decay_t< decltype(*std::begin(data))>
Compute variance using Welford's numerically stable algorithm.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
DynList< T > rep(const size_t n, const T &item)
Create a sequence of repeated items.
T product(const Container &container, const T &init=T{1})
Compute product of all elements.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
static struct argp_option options[]
void run_benchmarks(const BenchmarkConfig &config)
Sparse multivariate polynomial over an arbitrary coefficient ring.
Univariate polynomial ring arithmetic over generic coefficients.