fft/series_core.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <algorithm> | ||
| 4 | #include <cassert> | ||
| 5 | #include <concepts> | ||
| 6 | #include <cstddef> | ||
| 7 | #include <functional> | ||
| 8 | #include <optional> | ||
| 9 | #include <span> | ||
| 10 | #include <utility> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | #include "fft/multiply.hpp" | ||
| 14 | |||
| 15 | // ==== value types ==== | ||
| 16 | |||
| 17 | namespace ecnerwala::series { | ||
| 18 | |||
| 19 | // A series is either exact (a finite series, R[x] sitting inside R[[x]]: the | ||
| 20 | // length is just the support bound) or trunc (a known prefix of an infinite | ||
| 21 | // series: the length is the precision, and products truncate to it). | ||
| 22 | |||
| 23 | // Non-owning view of power series coefficients: the span pattern (contiguous | ||
| 24 | // window + series semantics), borrowed from an owning series-like type. | ||
| 25 | template <fft::engine E, bool exact_> | ||
| 26 | struct span { | ||
| 27 | using T = typename E::value_type; | ||
| 28 | using engine_t = E; | ||
| 29 | static constexpr bool exact_v = exact_; | ||
| 30 | |||
| 31 | ✗ | span() = default; | |
| 32 | 10549081 | explicit span(std::span<const T> s_) : s(s_) {} | |
| 33 | // exact -> trunc is implicit, trunc -> exact is explicit | ||
| 34 | template <bool oe> requires (oe != exact_) | ||
| 35 | ✗ | explicit(oe < exact_) span(span<E, oe> o) : s(o.coeffs()) {} | |
| 36 | |||
| 37 |
9/12✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 60 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 59 times.
✓ Branch 8 → 9 taken 55 times.
✓ Branch 8 → 10 taken 4 times.
✓ Branch 12 → 13 taken 3971680 times.
✓ Branch 12 → 15 taken 2 times.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 17 times.
✓ Branch 61 → 12 taken 578 times.
✓ Branch 61 → 62 taken 43 times.
|
6628756 | int len() const { return sz(s); } |
| 38 |
4/6✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 42 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 60 times.
✓ Branch 13 → 14 taken 3971648 times.
✓ Branch 13 → 15 taken 32 times.
|
3971946 | const T& operator[](int i) const { return s[size_t(i)]; } |
| 39 |
3/3✓ Branch 12 → 13 taken 2245 times.
✓ Branch 17 → 18 taken 59 times.
✓ Branch 27 → 28 taken 578 times.
|
5330 | auto begin() const { return s.begin(); } |
| 40 |
2/2✓ Branch 12 → 13 taken 1667 times.
✓ Branch 17 → 18 taken 59 times.
|
3856 | auto end() const { return s.end(); } |
| 41 | // engine primitives borrow through std::span's range constructor | ||
| 42 |
1/1✓ Branch 32 → 33 taken 6 times.
|
4625307 | std::span<const T> coeffs() const { return s; } |
| 43 | // the first n coefficients; requires n <= len(). | ||
| 44 | // Widening past len() is explicit: see with_len. | ||
| 45 | 5426 | span first(int n) const { | |
| 46 | 6302 | assert(n <= len()); | |
| 47 | 5426 | return span(s.first(size_t(n))); | |
| 48 | } | ||
| 49 | |||
| 50 | private: | ||
| 51 | std::span<const T> s; | ||
| 52 | }; | ||
| 53 | |||
| 54 | // `vec` represents both exact (finite) power series (R[x]) and prefixes of infinite power series (R[[x]]), depending on the flag. | ||
| 55 | // `exact` and `trunc` are aliases. | ||
| 56 | // | ||
| 57 | // Operators here are typically permissive: they will accept combinations of unequal types and lengths. | ||
| 58 | template <fft::engine E, bool exact_> | ||
| 59 |
21/21✓ Branch 11 → 16 taken 9 times.
✓ Branch 14 → 15 taken 20 times.
✓ Branch 15 → 16 taken 6 times.
✓ Branch 15 → 17 taken 578 times.
✓ Branch 25 → 26 taken 578 times.
✓ Branch 28 → 29 taken 10 times.
✓ Branch 31 → 32 taken 578 times.
✓ Branch 43 → 44 taken 1 time.
✓ Branch 48 → 59 taken 6 times.
✓ Branch 145 → 146 taken 5 times.
✓ Branch 151 → 152 taken 1 time.
✓ Branch 171 → 172 taken 1 time.
✓ Branch 306 → 307 taken 1 time.
✓ Branch 349 → 350 taken 1 time.
✓ Branch 393 → 394 taken 1 time.
✓ Branch 407 → 408 taken 1 time.
✓ Branch 507 → 508 taken 1 time.
✓ Branch 621 → 622 taken 1 time.
✓ Branch 733 → 734 taken 1 time.
✓ Branch 1041 → 1042 taken 1 time.
✓ Branch 1073 → 1074 taken 1 time.
|
1979598 | struct vec : public std::vector<typename E::value_type> { |
| 60 | using T = typename E::value_type; | ||
| 61 | using engine_t = E; | ||
| 62 | static constexpr bool exact_v = exact_; | ||
| 63 |
53/58✓ Branch 9 → 10 taken 59 times.
✓ Branch 10 → 11 taken 220 times.
✓ Branch 11 → 12 taken 14 times.
✓ Branch 12 → 13 taken 791 times.
✓ Branch 16 → 17 taken 115 times.
✓ Branch 17 → 18 taken 61 times.
✓ Branch 18 → 19 taken 34 times.
✓ Branch 20 → 21 taken 24 times.
✓ Branch 21 → 22 taken 59 times.
✓ Branch 27 → 28 taken 578 times.
✓ Branch 31 → 32 taken 11 times.
✓ Branch 33 → 34 taken 37 times.
✓ Branch 34 → 35 taken 11 times.
✓ Branch 40 → 57 taken 20 times.
✓ Branch 41 → 42 taken 537 times.
✗ Branch 42 → 59 not taken.
✗ Branch 48 → 53 not taken.
✗ Branch 48 → 55 not taken.
✗ Branch 48 → 65 not taken.
✓ Branch 52 → 53 taken 22 times.
✗ Branch 54 → 59 not taken.
✓ Branch 55 → 56 taken 59 times.
✓ Branch 56 → 59 taken 80 times.
✓ Branch 58 → 59 taken 6 times.
✓ Branch 58 → 61 taken 207 times.
✓ Branch 64 → 67 taken 10 times.
✓ Branch 66 → 67 taken 17 times.
✓ Branch 72 → 73 taken 2 times.
✓ Branch 73 → 74 taken 6 times.
✓ Branch 93 → 94 taken 1 time.
✓ Branch 103 → 104 taken 34 times.
✓ Branch 103 → 119 taken 6 times.
✓ Branch 106 → 107 taken 20 times.
✓ Branch 109 → 110 taken 20 times.
✓ Branch 116 → 117 taken 1 time.
✓ Branch 131 → 132 taken 6 times.
✓ Branch 136 → 137 taken 20 times.
✓ Branch 139 → 140 taken 20 times.
✓ Branch 158 → 159 taken 1 time.
✓ Branch 173 → 174 taken 6 times.
✓ Branch 185 → 186 taken 6 times.
✓ Branch 222 → 223 taken 34 times.
✓ Branch 228 → 229 taken 1 time.
✓ Branch 260 → 261 taken 1 time.
✓ Branch 266 → 267 taken 1 time.
✓ Branch 305 → 306 taken 1 time.
✓ Branch 354 → 355 taken 25 times.
✓ Branch 374 → 375 taken 1 time.
✓ Branch 380 → 381 taken 1 time.
✓ Branch 392 → 393 taken 6 times.
✓ Branch 402 → 403 taken 1 time.
✓ Branch 454 → 455 taken 1 time.
✓ Branch 608 → 609 taken 1 time.
✓ Branch 797 → 798 taken 1 time.
✓ Branch 880 → 881 taken 7 times.
✓ Branch 905 → 906 taken 1 time.
✓ Branch 1007 → 1008 taken 1 time.
✓ Branch 1078 → 1079 taken 1 time.
|
1975622 | using std::vector<T>::vector; |
| 64 | |||
| 65 | // a free const borrow of the coefficients: implicit | ||
| 66 |
2/4✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1974 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 59 times.
|
10536881 | operator span<E, exact_>() const { |
| 67 |
2/4✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 198 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 59 times.
|
10538079 | return span<E, exact_>(std::span<const T>(*this)); |
| 68 | } | ||
| 69 | |||
| 70 | // exact -> trunc is implicit, trunc -> exact is explicit | ||
| 71 | template <bool oe> requires (oe != exact_) | ||
| 72 |
2/2✓ Branch 726 → 727 taken 1 time.
✓ Branch 819 → 820 taken 1 time.
|
2 | explicit(oe < exact_) vec(const vec<E, oe>& p) : std::vector<T>(p) {} |
| 73 | template <bool oe> requires (oe != exact_) | ||
| 74 | 153 | explicit(oe < exact_) vec(vec<E, oe>&& p) : std::vector<T>(std::move(p)) {} | |
| 75 | |||
| 76 | // adopt a plain coefficient vector | ||
| 77 | 2652532 | explicit vec(std::vector<T> v) : std::vector<T>(std::move(v)) {} | |
| 78 | // materialize an owned copy of any borrowed series, of either exactness | ||
| 79 |
1/1✓ Branch 13 → 14 taken 6 times.
|
29 | explicit vec(span<E, exact_> s) : std::vector<T>(s.begin(), s.end()) {} |
| 80 |
1/1✓ Branch 13 → 14 taken 12 times.
|
56 | explicit vec(span<E, !exact_> s) : std::vector<T>(s.begin(), s.end()) {} |
| 81 | |||
| 82 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1667 times.
|
1831 | span<E, exact_> first(int n) const { return span<E, exact_>(*this).first(n); } |
| 83 | |||
| 84 |
2/4✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2651880 times.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 537 times.
|
13454280 | int len() const { |
| 85 |
43/61✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 31 times.
✓ Branch 4 → 5 taken 20 times.
✓ Branch 4 → 6 taken 11 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 20 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 40 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 12812345 times.
✓ Branch 9 → 10 taken 200 times.
✓ Branch 9 → 11 taken 40 times.
✗ Branch 9 → 22 not taken.
✓ Branch 10 → 11 taken 14 times.
✓ Branch 10 → 12 taken 46415355 times.
✗ Branch 10 → 38 not taken.
✓ Branch 12 → 6 taken 46413579 times.
✓ Branch 12 → 13 taken 2357 times.
✓ Branch 12 → 14 taken 22956811 times.
✗ Branch 12 → 37 not taken.
✗ Branch 12 → 68 not taken.
✗ Branch 12 → 78 not taken.
✓ Branch 14 → 8 taken 10144438 times.
✓ Branch 14 → 15 taken 42 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 644060 times.
✓ Branch 22 → 23 taken 644061 times.
✓ Branch 22 → 44 taken 1 time.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 260 not taken.
✓ Branch 31 → 32 taken 20 times.
✓ Branch 31 → 37 taken 80 times.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 17 times.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 595 times.
✓ Branch 36 → 19 taken 938 times.
✓ Branch 36 → 37 taken 616 times.
✓ Branch 36 → 56 taken 41 times.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 537 times.
✓ Branch 38 → 39 taken 20 times.
✓ Branch 38 → 40 taken 100 times.
✓ Branch 38 → 44 taken 80 times.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 537 times.
✓ Branch 41 → 23 taken 249 times.
✓ Branch 41 → 42 taken 571 times.
✓ Branch 47 → 48 taken 6 times.
✓ Branch 55 → 35 taken 60 times.
✓ Branch 55 → 56 taken 2 times.
✓ Branch 56 → 38 taken 249 times.
✓ Branch 56 → 57 taken 11 times.
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 621 times.
✓ Branch 60 → 32 taken 88 times.
✓ Branch 60 → 61 taken 3 times.
✓ Branch 61 → 12 taken 578 times.
✓ Branch 61 → 62 taken 43 times.
✗ Branch 336 → 337 not taken.
✓ Branch 336 → 338 taken 25 times.
|
82839431 | return int(this->size()); |
| 86 | } | ||
| 87 | ✗ | int degree() const requires (exact_) { | |
| 88 | ✗ | return len() - 1; | |
| 89 | } | ||
| 90 | ✗ | void extend(int sz) { | |
| 91 | ✗ | assert(sz >= len()); | |
| 92 | ✗ | this->resize(sz); | |
| 93 | } | ||
| 94 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 9 times.
|
15 | void shrink(int sz) { |
| 95 | 21 | assert(sz <= len()); | |
| 96 | 15 | this->resize(sz); | |
| 97 | 15 | } | |
| 98 | // multiply by x^n within the fixed precision window | ||
| 99 | ✗ | void shift_trunc(int n = 1) requires (!exact_) { | |
| 100 | ✗ | assert(n >= 0 && n <= len()); | |
| 101 | ✗ | std::rotate(this->begin(), this->end()-n, this->end()); | |
| 102 | ✗ | std::fill(this->begin(), this->begin()+n, T(0)); | |
| 103 | } | ||
| 104 | // divide by x^n and 0-pad within the fixed precision window | ||
| 105 | ✗ | void unshift_trunc(int n = 1) requires (!exact_) { | |
| 106 | ✗ | assert(n >= 0 && n <= len()); | |
| 107 | ✗ | std::fill(this->begin(), this->begin()+n, T(0)); | |
| 108 | ✗ | std::rotate(this->begin(), this->begin()+n, this->end()); | |
| 109 | } | ||
| 110 | |||
| 111 | // in-place forms require that the result's exactness/length must equal this operand's | ||
| 112 | template <bool oe> requires (exact_ <= oe) | ||
| 113 | ✗ | vec& operator += (const vec<E, oe>& o) { | |
| 114 | ✗ | if constexpr (exact_) { if (o.len() > len()) this->resize(o.len()); } | |
| 115 | ✗ | else if constexpr (!oe) { if (o.len() < len()) this->resize(o.len()); } | |
| 116 | ✗ | for (int i = 0; i < std::min(len(), o.len()); i++) { | |
| 117 | ✗ | (*this)[i] += o[i]; | |
| 118 | } | ||
| 119 | ✗ | return *this; | |
| 120 | } | ||
| 121 | template <bool oe> requires (exact_ <= oe) | ||
| 122 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 578 times.
|
612 | vec& operator -= (const vec<E, oe>& o) { |
| 123 | if constexpr (exact_) { if (o.len() > len()) this->resize(o.len()); } | ||
| 124 |
3/6✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 578 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 12 taken 578 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 39 taken 34 times.
|
680 | else if constexpr (!oe) { if (o.len() < len()) this->resize(o.len()); } |
| 125 |
6/8✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 10645015 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 10645015 times.
✓ Branch 17 → 8 taken 10644437 times.
✓ Branch 17 → 18 taken 578 times.
✓ Branch 63 → 27 taken 249 times.
✓ Branch 63 → 64 taken 34 times.
|
10645864 | for (int i = 0; i < std::min(len(), o.len()); i++) { |
| 126 |
2/2✓ Branch 8 → 9 taken 4673577 times.
✓ Branch 8 → 10 taken 5970860 times.
|
21289123 | (*this)[i] -= o[i]; |
| 127 | } | ||
| 128 | 612 | return *this; | |
| 129 | } | ||
| 130 | |||
| 131 | 69 | vec& operator *= (const T& n) { | |
| 132 |
8/8None:
✓ Branch 11 → 10 taken 4745532 times.
✓ Branch 11 → 12 taken 17 times.
✓ Branch 23 → 22 taken 4745532 times.
✓ Branch 23 → 24 taken 17 times.
✓ Branch 30 → 29 taken 4745532 times.
✓ Branch 30 → 31 taken 17 times.
ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::operator*=(modnum<998244353> const&):
✓ Branch 22 → 9 taken 411 times.
✓ Branch 22 → 23 taken 18 times.
|
14237112 | for (auto& v : *this) v *= n; |
| 133 | 18 | return *this; | |
| 134 | } | ||
| 135 | ✗ | friend vec operator * (const vec& a, const T& n) { | |
| 136 | ✗ | vec r(a.size()); | |
| 137 | ✗ | for (int i = 0; i < a.len(); i++) { | |
| 138 | ✗ | r[i] = a[i] * n; | |
| 139 | } | ||
| 140 | ✗ | return r; | |
| 141 | } | ||
| 142 | ✗ | friend vec operator * (const T& n, const vec& a) { | |
| 143 | ✗ | vec r(a.size()); | |
| 144 | ✗ | for (int i = 0; i < a.len(); i++) { | |
| 145 | ✗ | r[i] = n * a[i]; | |
| 146 | } | ||
| 147 | ✗ | return r; | |
| 148 | } | ||
| 149 | |||
| 150 | 1373 | vec& operator *= (const vec& o) { | |
| 151 |
1/1✓ Branch 4 → 5 taken 158 times.
|
2904 | return *this = (*this) * o; |
| 152 | } | ||
| 153 | |||
| 154 | }; | ||
| 155 | |||
| 156 | template <fft::engine E> using exact = vec<E, true>; | ||
| 157 | template <fft::engine E> using trunc = vec<E, false>; | ||
| 158 | |||
| 159 | // Series-like concepts: the binary operators below are written once as constrained | ||
| 160 | // templates and dispatch on which memoized transforms an operand carries. | ||
| 161 | // A series-like type exposes its engine/exactness and its coefficients as a | ||
| 162 | // span borrow of exactly len() coefficients; cached wrappers additionally | ||
| 163 | // expose their transform caches (filling them is logically const). | ||
| 164 | template <typename S> | ||
| 165 | concept like = fft::engine<typename S::engine_t> && requires(const S& s, int i) { | ||
| 166 | { S::exact_v } -> std::convertible_to<bool>; | ||
| 167 | { s.len() } -> std::same_as<int>; | ||
| 168 | { s[i] } -> std::convertible_to<const typename S::engine_t::value_type&>; | ||
| 169 | // borrows straight into the engine primitives | ||
| 170 | { std::span<const typename S::engine_t::value_type>(s) }; | ||
| 171 | // and into the series layer's own span, keeping the exactness tag | ||
| 172 | requires std::convertible_to<const S&, span<typename S::engine_t, S::exact_v>>; | ||
| 173 | // first(n): the first n coefficients, borrowed; requires n <= len(). | ||
| 174 | // The result is itself like (concepts can't self-reference). | ||
| 175 | // Cached types keep a cache in the result only when it still serves the whole borrow. | ||
| 176 | { s.first(i) } -> std::convertible_to<span<typename S::engine_t, S::exact_v>>; | ||
| 177 | }; | ||
| 178 | template <typename S> | ||
| 179 | concept exact_like = like<S> && S::exact_v; | ||
| 180 | template <typename S> | ||
| 181 | concept trunc_like = like<S> && !S::exact_v; | ||
| 182 | |||
| 183 | // carries one extendable transform of the whole coefficient sequence | ||
| 184 | template <typename S> | ||
| 185 | concept has_cache = like<S> && requires(const S& s) { | ||
| 186 | { s.cache() } -> std::same_as<fft::transformed<typename S::engine_t>&>; | ||
| 187 | }; | ||
| 188 | |||
| 189 | template <fft::engine E, bool exact_> | ||
| 190 | struct maybe_cached; | ||
| 191 | |||
| 192 | // A borrowed series paired with the transform serving it: the | ||
| 193 | // normalized operand form fed to the cached fft:: entry points. Models has_cache. | ||
| 194 | template <fft::engine E, bool exact_> | ||
| 195 | struct cached_span { | ||
| 196 | using engine_t = E; | ||
| 197 | static constexpr bool exact_v = exact_; | ||
| 198 | |||
| 199 | span<E, exact_> s; | ||
| 200 | std::reference_wrapper<fft::transformed<E>> f; | ||
| 201 | |||
| 202 | 2654741 | cached_span(span<E, exact_> s_, fft::transformed<E>& f_) : s(s_), f(f_) {} | |
| 203 | // exact -> trunc is implicit, trunc -> exact is explicit | ||
| 204 | template <bool oe> requires (oe != exact_) | ||
| 205 | ✗ | explicit(oe < exact_) cached_span(cached_span<E, oe> o) : s(span<E, exact_>(o.s)), f(o.f) {} | |
| 206 | |||
| 207 |
3/6✓ Branch 2 → 3 taken 20 times.
✗ Branch 2 → 4 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 20 times.
✓ Branch 10 → 11 taken 100 times.
✗ Branch 10 → 29 not taken.
|
740 | int len() const { return s.len(); } |
| 208 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 20 times.
|
220 | const typename E::value_type& operator[](int i) const { return s[i]; } |
| 209 |
1/1✓ Branch 14 → 15 taken 20 times.
|
4625281 | operator std::span<const typename E::value_type>() const { return s.coeffs(); } |
| 210 | 2655820 | operator span<E, exact_>() const { return s; } | |
| 211 | maybe_cached<E, exact_> first(int n) const; | ||
| 212 | 7283913 | fft::transformed<E>& cache() const { return f; } | |
| 213 | }; | ||
| 214 | |||
| 215 | // carries a whole-sequence cache only sometimes, decided at runtime | ||
| 216 | template <typename S> | ||
| 217 | concept has_cache_opt = like<S> && requires(const S& s) { | ||
| 218 | { s.cache_opt() } -> std::same_as<std::optional<std::reference_wrapper<fft::transformed<typename S::engine_t>>>>; | ||
| 219 | }; | ||
| 220 | |||
| 221 | namespace detail { | ||
| 222 | // the operand's whole cache, if it carries one | ||
| 223 | template <like S> | ||
| 224 | 13192720 | std::optional<std::reference_wrapper<fft::transformed<typename S::engine_t>>> cache_of(const S& s) { | |
| 225 | 13193180 | if constexpr (has_cache<S>) return s.cache(); | |
| 226 | 20 | else if constexpr (has_cache_opt<S>) return s.cache_opt(); | |
| 227 | 3862 | else return std::nullopt; | |
| 228 | } | ||
| 229 | /* namespace detail */ } | ||
| 230 | |||
| 231 | // A borrowed series which may carry the transform serving it: the runtime | ||
| 232 | // counterpart of cached_span in the borrow hierarchy | ||
| 233 | // prefix_cached/cached -> maybe_cached/cached_span -> span. | ||
| 234 | template <fft::engine E, bool exact_> | ||
| 235 | struct maybe_cached { | ||
| 236 | using T = typename E::value_type; | ||
| 237 | using engine_t = E; | ||
| 238 | static constexpr bool exact_v = exact_; | ||
| 239 | |||
| 240 | span<E, exact_> s; | ||
| 241 | std::optional<std::reference_wrapper<fft::transformed<E>>> f; | ||
| 242 | |||
| 243 | ✗ | explicit maybe_cached(span<E, exact_> s_) : s(s_) {} | |
| 244 | 23 | maybe_cached(span<E, exact_> s_, fft::transformed<E>& f_) : s(s_), f(f_) {} | |
| 245 | ✗ | maybe_cached(cached_span<E, exact_> c) : s(c.s), f(c.f) {} | |
| 246 | // borrow any like operand whole, taking along whatever cache it carries | ||
| 247 | template <like S> requires std::same_as<typename S::engine_t, E> && (S::exact_v == exact_) | ||
| 248 | ✗ | maybe_cached(const S& o) : s(o), f(detail::cache_of(o)) {} | |
| 249 | |||
| 250 | 6 | int len() const { return s.len(); } | |
| 251 | 6 | const T& operator[](int i) const { return s[i]; } | |
| 252 | ✗ | operator std::span<const T>() const { return s.coeffs(); } | |
| 253 | 20 | operator span<E, exact_>() const { return s; } | |
| 254 | ✗ | maybe_cached first(int n) const { | |
| 255 | ✗ | return n == len() ? *this : maybe_cached(s.first(n)); | |
| 256 | } | ||
| 257 | 20 | std::optional<std::reference_wrapper<fft::transformed<E>>> cache_opt() const { return f; } | |
| 258 | }; | ||
| 259 | |||
| 260 | template <fft::engine E, bool exact_> | ||
| 261 | ✗ | maybe_cached<E, exact_> cached_span<E, exact_>::first(int n) const { | |
| 262 | ✗ | return maybe_cached<E, exact_>(*this).first(n); | |
| 263 | } | ||
| 264 | |||
| 265 | // An owned series copy at an adjusted logical length: the result of with_len. | ||
| 266 | // Carries a reference to a source cache when it still serves the copied | ||
| 267 | // coefficients (a zero tail doesn't change the transform), so the source | ||
| 268 | // must outlive the result. | ||
| 269 | template <fft::engine E> | ||
| 270 | struct resized { | ||
| 271 | using T = typename E::value_type; | ||
| 272 | using engine_t = E; | ||
| 273 | static constexpr bool exact_v = false; | ||
| 274 | |||
| 275 | trunc<E> s; | ||
| 276 | std::optional<std::reference_wrapper<fft::transformed<E>>> f; | ||
| 277 | |||
| 278 | ✗ | int len() const { return s.len(); } | |
| 279 | ✗ | const T& operator[](int i) const { return s[size_t(i)]; } | |
| 280 | ✗ | operator std::span<const T>() const { return std::span<const T>(s); } | |
| 281 | ✗ | operator span<E, false>() const { return s; } | |
| 282 | ✗ | maybe_cached<E, false> first(int n) const { | |
| 283 | ✗ | span<E, false> v = s; | |
| 284 | ✗ | if (n == len() && f) return {v, f->get()}; | |
| 285 | ✗ | return maybe_cached<E, false>(v.first(n)); | |
| 286 | } | ||
| 287 | ✗ | std::optional<std::reference_wrapper<fft::transformed<E>>> cache_opt() const { return f; } | |
| 288 | }; | ||
| 289 | |||
| 290 | // copy any operand to logical length n: extending zero-fills, shrinking truncates | ||
| 291 | template <like S> | ||
| 292 | ✗ | resized<typename S::engine_t> with_len(const S& s, int n) { | |
| 293 | using E = typename S::engine_t; | ||
| 294 | using T = typename E::value_type; | ||
| 295 | ✗ | auto p = s.first(std::min(n, s.len())); | |
| 296 | ✗ | resized<E> r; | |
| 297 | ✗ | r.s.assign(size_t(n), T{}); | |
| 298 | ✗ | std::span<const T> pc(p); | |
| 299 | ✗ | std::copy(pc.begin(), pc.end(), r.s.begin()); | |
| 300 | ✗ | r.f = detail::cache_of(p); | |
| 301 | ✗ | return r; | |
| 302 | } | ||
| 303 | |||
| 304 | // carries memoized transforms of power-of-two prefixes (see prefix_cached): | ||
| 305 | // product operands truncate to a covered scale to reuse them. | ||
| 306 | // Trunc-only: an exact operand participates whole, so has_cache covers it. | ||
| 307 | template <typename S> | ||
| 308 | concept has_prefix_cache = like<S> && !S::exact_v && requires(const S& s, int n) { | ||
| 309 | { s.prefix_cache(n) } -> std::same_as<fft::transformed<typename S::engine_t>&>; | ||
| 310 | }; | ||
| 311 | |||
| 312 | // Wrapper around vec which caches the transform of the whole series. | ||
| 313 | // Ops exploit the cache whenever the whole span participates; a trunc series' | ||
| 314 | // whole-sequence transform is still useful for middle products and repeated | ||
| 315 | // full-precision use. | ||
| 316 | template <fft::engine E, bool exact_> | ||
| 317 |
2/2✓ Branch 13 → 14 taken 1325940 times.
✓ Branch 17 → 18 taken 11 times.
|
19131946 | struct cached { |
| 318 | using T = typename E::value_type; | ||
| 319 | using engine_t = E; | ||
| 320 | static constexpr bool exact_v = exact_; | ||
| 321 | |||
| 322 | 6593380 | cached() = default; | |
| 323 | // moving coefficients in or out is free: implicit on rvalues, explicit copy otherwise | ||
| 324 | 4624051 | cached(vec<E, exact_>&& s_) : s(std::move(s_)) {} | |
| 325 | 43 | explicit cached(const vec<E, exact_>& s_) : s(s_) {} | |
| 326 | 182 | operator vec<E, exact_>() && { return std::move(s); } | |
| 327 | |||
| 328 |
22/33✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2651900 times.
✓ Branch 4 → 5 taken 2651880 times.
✓ Branch 4 → 6 taken 31 times.
✗ Branch 4 → 8 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2651891 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 11 times.
✓ Branch 7 → 8 taken 8 times.
✓ Branch 7 → 9 taken 2651880 times.
✓ Branch 7 → 10 taken 3 times.
✓ Branch 8 → 9 taken 8 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 11 times.
✓ Branch 11 → 12 taken 11 times.
✓ Branch 15 → 16 taken 260 times.
✗ Branch 15 → 43 not taken.
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 7 times.
✓ Branch 24 → 25 taken 6 times.
✗ Branch 24 → 91 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 3 times.
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 1 time.
✓ Branch 30 → 31 taken 1 time.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 1 time.
✓ Branch 42 → 43 taken 7 times.
✓ Branch 42 → 44 taken 260 times.
✓ Branch 66 → 35 taken 39 times.
✓ Branch 66 → 67 taken 1 time.
|
2654584 | int len() const { return s.len(); } |
| 329 | // unwrap to the owned coefficients | ||
| 330 | ✗ | const vec<E, exact_>& uncached() const { return s; } | |
| 331 | 1327576 | const T& operator[](int i) const { return s[size_t(i)]; } | |
| 332 | 8 | auto begin() const { return s.cbegin(); } | |
| 333 | 6 | auto end() const { return s.cend(); } | |
| 334 |
5/7✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 11 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 11 times.
✓ Branch 7 → 8 taken 11 times.
✓ Branch 7 → 9 taken 9 times.
✓ Branch 9 → 10 taken 9 times.
|
1119 | operator span<E, exact_>() const { return s; } |
| 335 | ✗ | maybe_cached<E, exact_> first(int n) const { | |
| 336 | ✗ | return n == len() ? maybe_cached<E, exact_>(s, f) : maybe_cached<E, exact_>(s.first(n)); | |
| 337 | } | ||
| 338 | // the transform of the coefficients, fed to the cached fft:: entry points alongside them | ||
| 339 | 10533209 | fft::transformed<E>& cache() const { return f; } | |
| 340 | |||
| 341 | template <like S> | ||
| 342 | 10 | friend bool operator==(const cached& a, const S& b) { | |
| 343 | 10 | span<E, S::exact_v> bs = b; | |
| 344 |
10/18bool ecnerwala::series::operator==<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 19 → 20 taken 3 times.
✗ Branch 19 → 41 not taken.
✓ Branch 30 → 31 taken 3 times.
✓ Branch 41 → 42 taken 3 times.
✗ Branch 41 → 43 not taken.
✓ Branch 43 → 44 taken 3 times.
✗ Branch 43 → 54 not taken.
✓ Branch 54 → 55 taken 3 times.
✗ Branch 54 → 56 not taken.
bool ecnerwala::series::operator==<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 22 → 23 taken 7 times.
✗ Branch 22 → 44 not taken.
✓ Branch 33 → 34 taken 7 times.
✓ Branch 44 → 45 taken 7 times.
✗ Branch 44 → 46 not taken.
✓ Branch 46 → 47 taken 7 times.
✗ Branch 46 → 57 not taken.
✓ Branch 57 → 58 taken 7 times.
✗ Branch 57 → 59 not taken.
|
70 | return a.len() == bs.len() && std::equal(a.s.begin(), a.s.end(), bs.begin()); |
| 345 | } | ||
| 346 | |||
| 347 | private: | ||
| 348 | vec<E, exact_> s; | ||
| 349 | mutable fft::transformed<E> f; // memoized transform: filling it is logically const | ||
| 350 | }; | ||
| 351 | |||
| 352 | template <fft::engine E> using cached_exact = cached<E, true>; | ||
| 353 | template <fft::engine E> using cached_trunc = cached<E, false>; | ||
| 354 | |||
| 355 | namespace detail { | ||
| 356 | // Normalize a whole-span operand to a cached_span: the coefficients borrowed | ||
| 357 | // together with the cache serving them (the operand's own, or tmp otherwise). | ||
| 358 | // The whole-span multiply/square/middle_product paths run entirely on this form. | ||
| 359 | template <like S> | ||
| 360 | 10536640 | cached_span<typename S::engine_t, S::exact_v> as_cached_span(const S& s, fft::transformed<typename S::engine_t>& tmp) { | |
| 361 |
2/4ecnerwala::series::cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 20 times.
ecnerwala::series::cached_span<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 7879964 times.
|
10536640 | auto co = cache_of(s); |
| 362 |
21/42ecnerwala::series::cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t::transformed&):
✓ Branch 13 → 14 taken 20 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✓ Branch 2 → 3 taken 96 times.
✗ Branch 2 → 4 not taken.
✓ Branch 13 → 14 taken 20 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t::transformed&):
✓ Branch 13 → 14 taken 20 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::engine_t, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::engine_t::transformed&):
✓ Branch 13 → 14 taken 20 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✓ Branch 2 → 3 taken 2563 times.
✗ Branch 2 → 4 not taken.
✓ Branch 13 → 14 taken 461 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✓ Branch 2 → 3 taken 2652017 times.
✗ Branch 2 → 4 not taken.
✓ Branch 13 → 14 taken 367 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t::transformed&):
✓ Branch 13 → 14 taken 20 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✓ Branch 2 → 3 taken 96 times.
✗ Branch 2 → 4 not taken.
✓ Branch 13 → 14 taken 20 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::maybe_cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::maybe_cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::maybe_cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::maybe_cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::maybe_cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✓ Branch 13 → 14 taken 20 times.
✗ Branch 13 → 18 not taken.
ecnerwala::series::cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 17 taken 25 times.
ecnerwala::series::cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::engine_t::transformed&):
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 17 taken 25 times.
ecnerwala::series::cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 17 taken 24 times.
ecnerwala::series::cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 20 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 17 taken 30 times.
ecnerwala::series::cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 17 taken 25 times.
ecnerwala::series::cached_span<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::detail::as_cached_span<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✓ Branch 4 → 5 taken 7879964 times.
✗ Branch 4 → 6 not taken.
✓ Branch 15 → 16 taken 787 times.
✗ Branch 15 → 20 not taken.
|
10540279 | return {s, co ? co->get() : tmp}; |
| 363 | } | ||
| 364 | /* namespace detail */ } | ||
| 365 | |||
| 366 | // Newton inversion: 1/a mod x^a.len(). Generic over any engine; per doubling step | ||
| 367 | // n -> m = 2n this is 5 transforms of size m, reusing b's transform for both circular | ||
| 368 | // products; in each product the wraparound only contaminates coefficients [0, n) | ||
| 369 | // which are already known. | ||
| 370 | // | ||
| 371 | // This is correct for non-commutative rings. | ||
| 372 | // TODO: reuse/populate the operand's whole/prefix transform caches | ||
| 373 | template <trunc_like S> | ||
| 374 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 146 times.
|
180 | trunc<typename S::engine_t> ps_inv(const S& a) { |
| 375 | using E = typename S::engine_t; | ||
| 376 | using T = typename E::value_type; | ||
| 377 | 180 | int N = a.len(); | |
| 378 |
1/2✓ Branch 5 → 6 taken 146 times.
✗ Branch 5 → 46 not taken.
|
248 | trunc<E> r(size_t(N), T{}); |
| 379 |
5/10ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 238 not taken.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 318 not taken.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 5 → 6 taken 146 times.
✗ Branch 5 → 46 not taken.
✓ Branch 21 → 22 taken 31 times.
✗ Branch 21 → 318 not taken.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 286 not taken.
|
180 | if (N == 0) return r; |
| 380 |
2/2✓ Branch 6 → 7 taken 137 times.
✓ Branch 6 → 8 taken 9 times.
|
180 | int s = nextPow2(N); |
| 381 |
5/5ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 30 → 31 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 30 → 31 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 8 → 9 taken 146 times.
✓ Branch 30 → 31 taken 31 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 30 → 31 taken 1 time.
|
214 | std::vector<T> b(size_t(s), T{}); |
| 382 | 214 | b[0] = inv(a[0]); | |
| 383 |
10/10ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 159 → 50 taken 9 times.
✓ Branch 159 → 160 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 239 → 50 taken 9 times.
✓ Branch 239 → 240 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 42 → 11 taken 1667 times.
✓ Branch 42 → 43 taken 146 times.
✓ Branch 239 → 50 taken 106 times.
✓ Branch 239 → 240 taken 31 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 207 → 50 taken 9 times.
✓ Branch 207 → 208 taken 1 time.
|
2485 | for (int n = 1; n < N; n *= 2) { |
| 384 | 1800 | int m = 2 * n; | |
| 385 |
5/5ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 61 → 62 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 61 → 62 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 12 → 13 taken 1667 times.
✓ Branch 61 → 62 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 61 → 62 taken 9 times.
|
1800 | auto ta = E::transform(a.first(std::min(N, m)), m); |
| 386 |
6/7ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 69 → 70 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 69 → 70 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 1667 times.
✓ Branch 15 → 16 taken 1667 times.
✓ Branch 69 → 70 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 69 → 70 taken 9 times.
|
1800 | auto tb = E::transform(std::span<const T>(b).first(n), m); |
| 387 | // e = a*b mod x^m; only e[n..m) is needed (and is wraparound-free). | ||
| 388 |
6/7ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 72 → 73 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 72 → 73 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 16 → 17 taken 1667 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 1667 times.
✓ Branch 72 → 73 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 72 → 73 taken 9 times.
|
1800 | auto e = fft::buffer_pool<T>::get(m); |
| 389 |
10/10ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 79 → 80 taken 9 times.
✓ Branch 81 → 82 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 79 → 80 taken 9 times.
✓ Branch 81 → 82 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 19 → 20 taken 1667 times.
✓ Branch 20 → 21 taken 1667 times.
✓ Branch 79 → 80 taken 106 times.
✓ Branch 81 → 82 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 79 → 80 taken 9 times.
✓ Branch 81 → 82 taken 9 times.
|
1800 | E::finish(E::mul(ta, tb, m), e.span()); |
| 390 |
10/10ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 99 → 85 taken 511 times.
✓ Branch 99 → 100 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 115 → 101 taken 511 times.
✓ Branch 115 → 116 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 24 → 23 taken 22233283 times.
✓ Branch 24 → 25 taken 1667 times.
✓ Branch 115 → 101 taken 1309 times.
✓ Branch 115 → 116 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 99 → 85 taken 511 times.
✓ Branch 99 → 100 taken 9 times.
|
22240767 | for (int i = 0; i < n; i++) e[i] = T{}; |
| 391 |
5/5ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 110 → 111 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 126 → 127 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 25 → 26 taken 1667 times.
✓ Branch 126 → 127 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 110 → 111 taken 9 times.
|
1933 | auto te = E::transform(std::span<const T>(e.span()), m); |
| 392 |
6/7ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 114 → 115 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 130 → 131 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 26 → 27 taken 1667 times.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 1667 times.
✓ Branch 130 → 131 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 114 → 115 taken 9 times.
|
1800 | auto c = fft::buffer_pool<T>::get(m); |
| 393 | // b' = 2b - b*(a*b): keep b on the left of e = a*b | ||
| 394 |
10/10ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 121 → 122 taken 9 times.
✓ Branch 123 → 124 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 137 → 138 taken 9 times.
✓ Branch 139 → 140 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 29 → 30 taken 1667 times.
✓ Branch 30 → 31 taken 1667 times.
✓ Branch 137 → 138 taken 106 times.
✓ Branch 139 → 140 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 121 → 122 taken 9 times.
✓ Branch 123 → 124 taken 9 times.
|
1800 | E::finish(E::mul(tb, te, m), c.span()); |
| 395 |
10/10ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 147 → 127 taken 297 times.
✓ Branch 147 → 148 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 179 → 159 taken 297 times.
✓ Branch 179 → 180 taken 9 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 35 → 33 taken 18840532 times.
✓ Branch 35 → 36 taken 1667 times.
✓ Branch 179 → 159 taken 848 times.
✓ Branch 179 → 180 taken 106 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 147 → 127 taken 297 times.
✓ Branch 147 → 148 taken 9 times.
|
18845810 | for (int i = n; i < std::min(m, N); i++) b[i] = -c[i]; |
| 396 | } | ||
| 397 |
4/4ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&):
✓ Branch 171 → 172 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&):
✓ Branch 251 → 252 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 251 → 252 taken 31 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t, false> ecnerwala::series::ps_inv<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&):
✓ Branch 219 → 220 taken 1 time.
|
350 | std::copy(b.begin(), b.begin() + N, r.begin()); |
| 398 | 180 | return r; | |
| 399 | 180 | } | |
| 400 | // TODO: operator / can be done slightly faster than ps_inv: | ||
| 401 | // we only need the n/2 terms of ps_inv(), and can do the last Newton step directly on the quotient | ||
| 402 | |||
| 403 | // Both consume whole-sequence transforms by nature (the full span always | ||
| 404 | // participates), so only whole caches apply, never prefix caches. | ||
| 405 | template <like A> | ||
| 406 | 30 | auto square(const A& a) { | |
| 407 | using E = typename A::engine_t; | ||
| 408 | using T = typename E::value_type; | ||
| 409 | 30 | fft::transformed<E> ta_; | |
| 410 | 30 | auto av = detail::as_cached_span(a, ta_); | |
| 411 | if constexpr (A::exact_v) { | ||
| 412 | // like operator*, an exact square returns has_cache, adopting the | ||
| 413 | // pointwise product as the result's transform when the engine supports it | ||
| 414 | 6 | std::vector<T> coeffs; | |
| 415 | 6 | fft::transformed<E> f; | |
| 416 |
2/2auto ecnerwala::series::square<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 16 → 17 taken 4 times.
auto ecnerwala::series::square<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 16 → 17 taken 2 times.
|
6 | fft::square_cached<E>(av, av.cache(), coeffs, f); |
| 417 | 30 | cached<E, true> w(exact<E>(std::move(coeffs))); | |
| 418 | 12 | w.cache() = std::move(f); | |
| 419 | 6 | return w; | |
| 420 | 12 | } else { | |
| 421 | 96 | trunc<E> r(size_t(a.len()), T{}); | |
| 422 |
1/1✓ Branch 34 → 35 taken 24 times.
|
48 | fft::square<E>(av, av.cache(), std::span<T>(r)); |
| 423 | 24 | return r; | |
| 424 | } | ||
| 425 | 30 | } | |
| 426 | |||
| 427 | // a*b + c*d, all exact; returns has_cache, adopting the summed pointwise | ||
| 428 | // product as the result's transform when the engine supports it. Reuses each | ||
| 429 | // operand's whole cache. Requires a*b and c*d to have equal length. | ||
| 430 | template <like A, like B, like C, like D> | ||
| 431 | requires fft::same_engine<A, B> && fft::same_engine<A, C> && fft::same_engine<A, D> | ||
| 432 | && A::exact_v && B::exact_v && C::exact_v && D::exact_v | ||
| 433 | 644116 | cached<typename A::engine_t, true> multiply_add2( | |
| 434 | const A& a, const B& b, const C& c, const D& d) { | ||
| 435 | using E = typename A::engine_t; | ||
| 436 | using T = typename E::value_type; | ||
| 437 | 644116 | fft::transformed<E> ta_, tb_, tc_, td_; | |
| 438 | 644116 | auto av = detail::as_cached_span(a, ta_), bv = detail::as_cached_span(b, tb_); | |
| 439 | 644116 | auto cv = detail::as_cached_span(c, tc_), dv = detail::as_cached_span(d, td_); | |
| 440 | 644116 | std::vector<T> coeffs; | |
| 441 |
1/1✓ Branch 2 → 3 taken 644051 times.
|
644116 | fft::transformed<E> f; |
| 442 |
2/2✓ Branch 2 → 3 taken 644051 times.
✓ Branch 52 → 53 taken 65 times.
|
644311 | fft::multiply_add2_cached<E>( |
| 443 | av, av.cache(), | ||
| 444 | bv, bv.cache(), | ||
| 445 | cv, cv.cache(), | ||
| 446 | dv, dv.cache(), | ||
| 447 | coeffs, f | ||
| 448 | ); | ||
| 449 | 644376 | cached<E, true> w(exact<E>(std::move(coeffs))); | |
| 450 | 644116 | w.cache() = std::move(f); | |
| 451 | 644181 | return w; | |
| 452 | 644441 | } | |
| 453 | |||
| 454 | // coefficients [b.len()-1, a.len()) of a*b; requires a.len() >= b.len() > 0. | ||
| 455 | // The kernel b participates whole, so it must be exact; the result mirrors a's kind. | ||
| 456 | template <like A, exact_like B> requires fft::same_engine<A, B> | ||
| 457 | 2652143 | vec<typename A::engine_t, A::exact_v> middle_product(const A& a, const B& b) { | |
| 458 | using E = typename A::engine_t; | ||
| 459 | 2652143 | fft::transformed<E> ta_, tb_; | |
| 460 | 2652143 | auto av = detail::as_cached_span(a, ta_); | |
| 461 |
1/1✓ Branch 2 → 3 taken 2651880 times.
|
2652143 | auto bv = detail::as_cached_span(b, tb_); |
| 462 |
3/3ecnerwala::series::vec<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::middle_product<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 27 → 28 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::middle_product<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 2 → 3 taken 2651880 times.
✓ Branch 27 → 28 taken 262 times.
|
5304549 | return vec<E, A::exact_v>(fft::middle_product<E>( |
| 463 | av, av.cache(), | ||
| 464 | bv, bv.cache() | ||
| 465 | 2652669 | )); | |
| 466 | 2652406 | } | |
| 467 | |||
| 468 | namespace detail { | ||
| 469 | 1327890 | template <bool ea, bool eb> int product_prec(int la, int lb) { | |
| 470 |
2/4✓ Branch 2 → 3 taken 1326258 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 1326258 times.
✗ Branch 3 → 5 not taken.
|
1326258 | if constexpr (ea && eb) return la > 0 && lb > 0 ? la + lb - 1 : 0; |
| 471 | 1632 | else return ea ? lb : eb ? la : std::min(la, lb); | |
| 472 | } | ||
| 473 | |||
| 474 | // Normalize a product operand at the given precision to a borrowed series + the | ||
| 475 | // whole cache serving it: a prefix cache at scale nextPow2(prec), or the whole | ||
| 476 | // span with the operand's own cache, or a truncated span with the caller's | ||
| 477 | // throwaway cache. | ||
| 478 | // A whole cache of an over-length operand (len > prec, which pins the other, | ||
| 479 | // necessarily trunc, operand's span at exactly prec) is only worth using when | ||
| 480 | // the untruncated span doesn't grow the transform size: a 2x'd inverse | ||
| 481 | // transform costs more than the saved forward transform. | ||
| 482 | template <like S> | ||
| 483 |
5/10auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 96 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2543 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 106 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 96 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2651891 times.
|
2655740 | auto product_operand(const S& s, int prec, fft::transformed<typename S::engine_t>& tmp) { |
| 484 | using E = typename S::engine_t; | ||
| 485 | if constexpr (has_prefix_cache<S>) { | ||
| 486 |
1/1✓ Branch 21 → 22 taken 20 times.
|
40 | return s.first(std::min(s.len(), nextPow2(prec))); |
| 487 | } else { | ||
| 488 | 2655720 | span<E, S::exact_v> v = s; | |
| 489 |
7/14auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✓ Branch 2 → 3 taken 20 times.
✗ Branch 2 → 6 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 96 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 2543 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 106 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 96 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 20 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✓ Branch 4 → 5 taken 2651891 times.
✗ Branch 4 → 8 not taken.
|
2656668 | int used = std::min(v.len(), prec); |
| 490 |
19/38auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✓ Branch 24 → 25 taken 20 times.
✗ Branch 24 → 51 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::engine_t::transformed&):
✓ Branch 24 → 25 taken 20 times.
✗ Branch 24 → 51 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✓ Branch 2 → 3 taken 20 times.
✗ Branch 2 → 6 not taken.
✓ Branch 24 → 25 taken 20 times.
✗ Branch 24 → 51 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✓ Branch 24 → 25 taken 20 times.
✗ Branch 24 → 51 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 96 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 2543 times.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 48 taken 438 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 106 times.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 48 taken 74 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 96 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t::transformed&):
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 44 taken 20 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t::transformed&):
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 44 taken 20 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 20 times.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 44 taken 20 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t::transformed&):
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 44 taken 20 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✓ Branch 26 → 27 taken 3 times.
✗ Branch 26 → 57 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✓ Branch 4 → 5 taken 2651891 times.
✗ Branch 4 → 8 not taken.
✓ Branch 26 → 27 taken 273 times.
✗ Branch 26 → 57 not taken.
|
2656668 | if (auto co = cache_of(s)) { |
| 491 |
9/38auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✓ Branch 33 → 34 taken 20 times.
✗ Branch 33 → 45 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::engine_t::transformed&):
✓ Branch 33 → 34 taken 20 times.
✗ Branch 33 → 45 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✓ Branch 3 → 4 taken 20 times.
✗ Branch 3 → 5 not taken.
✓ Branch 33 → 34 taken 20 times.
✗ Branch 33 → 45 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✓ Branch 33 → 34 taken 20 times.
✗ Branch 33 → 45 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 42 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 42 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t::transformed&):
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 38 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t::transformed&):
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 38 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 38 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t::transformed&):
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 38 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✓ Branch 37 → 38 taken 1 time.
✓ Branch 37 → 51 taken 2 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2651891 times.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 51 taken 273 times.
|
2652704 | if (s.len() <= prec || fft::detail::conv_size_for(s.len() + prec - 1).n |
| 492 |
11/38auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✓ Branch 44 → 45 taken 15 times.
✓ Branch 44 → 51 taken 5 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true>::engine_t::transformed&):
✓ Branch 44 → 45 taken 15 times.
✓ Branch 44 → 51 taken 5 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✓ Branch 4 → 5 taken 18 times.
✓ Branch 4 → 6 taken 2 times.
✓ Branch 44 → 45 taken 15 times.
✓ Branch 44 → 51 taken 5 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, int, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✓ Branch 44 → 45 taken 15 times.
✓ Branch 44 → 51 taken 5 times.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>::engine_t::transformed&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 48 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 48 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, int, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>::engine_t::transformed&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>::engine_t::transformed&):
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 44 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>::engine_t::transformed&):
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 44 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 44 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> >(ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&, int, ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false>::engine_t::transformed&):
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 44 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, int, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t::transformed&):
✓ Branch 50 → 51 taken 1 time.
✗ Branch 50 → 57 not taken.
auto ecnerwala::series::detail::product_operand<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, int, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t::transformed&):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 57 not taken.
|
101 | == fft::detail::conv_size_for(2 * prec - 1).n) { |
| 493 | 2652245 | return cached_span<E, S::exact_v>{v, co->get()}; | |
| 494 | } | ||
| 495 | } | ||
| 496 | 3475 | return cached_span<E, S::exact_v>{v.first(used), tmp}; | |
| 497 | } | ||
| 498 | } | ||
| 499 | /* namespace detail */ } | ||
| 500 | |||
| 501 | template <like A, like B> requires fft::same_engine<A, B> | ||
| 502 | 3 | vec<typename A::engine_t, A::exact_v && B::exact_v> operator + (const A& a, const B& b) { | |
| 503 | using T = typename A::engine_t::value_type; | ||
| 504 | 5 | int n = (A::exact_v && B::exact_v) ? std::max(a.len(), b.len()) | |
| 505 | 4 | : A::exact_v ? b.len() : B::exact_v ? a.len() : std::min(a.len(), b.len()); | |
| 506 | 9 | vec<typename A::engine_t, A::exact_v && B::exact_v> r(size_t(n), T(0)); | |
| 507 |
6/6ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::operator+<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 91 → 37 taken 23 times.
✓ Branch 91 → 92 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::operator+<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 75 → 21 taken 23 times.
✓ Branch 75 → 76 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::operator+<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 91 → 37 taken 37 times.
✓ Branch 91 → 92 taken 1 time.
|
86 | for (int i = 0; i < n; i++) { |
| 508 |
7/12ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::operator+<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 46 → 47 taken 23 times.
✗ Branch 46 → 55 not taken.
✓ Branch 67 → 68 taken 23 times.
✗ Branch 67 → 76 not taken.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::operator+<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 30 → 31 taken 23 times.
✗ Branch 30 → 39 not taken.
✓ Branch 51 → 52 taken 23 times.
✗ Branch 51 → 60 not taken.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::operator+<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 46 → 47 taken 23 times.
✓ Branch 46 → 55 taken 14 times.
✓ Branch 67 → 68 taken 37 times.
✗ Branch 67 → 76 not taken.
|
263 | r[i] = (i < a.len() ? a[i] : T(0)) + (i < b.len() ? b[i] : T(0)); |
| 509 | } | ||
| 510 | 3 | return r; | |
| 511 | } | ||
| 512 | template <like A, like B> requires fft::same_engine<A, B> | ||
| 513 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 578 times.
|
614 | vec<typename A::engine_t, A::exact_v && B::exact_v> operator - (const A& a, const B& b) { |
| 514 | using T = typename A::engine_t::value_type; | ||
| 515 | 38 | int n = (A::exact_v && B::exact_v) ? std::max(a.len(), b.len()) | |
| 516 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 578 times.
|
714 | : A::exact_v ? b.len() : B::exact_v ? a.len() : std::min(a.len(), b.len()); |
| 517 | 686 | vec<typename A::engine_t, A::exact_v && B::exact_v> r(size_t(n), T(0)); | |
| 518 |
8/8ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::operator-<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 75 → 21 taken 23 times.
✓ Branch 75 → 76 taken 1 time.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::operator-<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 20 → 8 taken 12812331 times.
✓ Branch 20 → 21 taken 578 times.
✓ Branch 91 → 37 taken 339 times.
✓ Branch 91 → 92 taken 34 times.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::operator-<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 91 → 37 taken 37 times.
✓ Branch 91 → 92 taken 1 time.
|
12813344 | for (int i = 0; i < n; i++) { |
| 519 |
9/16ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::operator-<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 30 → 31 taken 23 times.
✗ Branch 30 → 39 not taken.
✓ Branch 51 → 52 taken 23 times.
✗ Branch 51 → 60 not taken.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>::exact_v> ecnerwala::series::operator-<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 10 → 11 taken 12812331 times.
✗ Branch 10 → 12 not taken.
✓ Branch 14 → 15 taken 12812331 times.
✗ Branch 14 → 16 not taken.
✓ Branch 46 → 47 taken 339 times.
✗ Branch 46 → 55 not taken.
✓ Branch 67 → 68 taken 339 times.
✗ Branch 67 → 76 not taken.
ecnerwala::series::vec<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::engine_t, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v&&ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>::exact_v> ecnerwala::series::operator-<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 46 → 47 taken 23 times.
✓ Branch 46 → 55 taken 14 times.
✓ Branch 67 → 68 taken 37 times.
✗ Branch 67 → 76 not taken.
|
38438204 | r[i] = (i < a.len() ? a[i] : T(0)) - (i < b.len() ? b[i] : T(0)); |
| 520 | } | ||
| 521 | 614 | return r; | |
| 522 | } | ||
| 523 | |||
| 524 | // The single multiplication operator: each operand is normalized to a borrowed | ||
| 525 | // series + whole cache (see detail::product_operand), then multiplied once. | ||
| 526 | // An exact x exact product returns a has_cache result, going through | ||
| 527 | // fft::multiply_cached so the pointwise product is adopted as the result's | ||
| 528 | // transform whenever the engine supports it. | ||
| 529 | template <like A, like B> requires fft::same_engine<A, B> | ||
| 530 | 1327890 | auto operator * (const A& a, const B& b) { | |
| 531 | using E = typename A::engine_t; | ||
| 532 | using T = typename E::value_type; | ||
| 533 |
6/12auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1266 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 53 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 11 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1325940 times.
|
1327890 | constexpr bool ea = A::exact_v, eb = B::exact_v; |
| 534 |
6/12auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1266 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 53 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 11 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1325940 times.
|
1328717 | int prec = detail::product_prec<ea, eb>(a.len(), b.len()); |
| 535 |
69/130auto ecnerwala::series::operator*<ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > >, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 20 → 21 taken 8 times.
✗ Branch 20 → 40 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 49 taken 8 times.
auto ecnerwala::series::operator*<ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > >, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > >(ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&):
✓ Branch 23 → 24 taken 2 times.
✗ Branch 23 → 46 not taken.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&):
✓ Branch 6 → 7 taken 48 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 48 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&):
✓ Branch 20 → 21 taken 8 times.
✗ Branch 20 → 40 not taken.
✓ Branch 28 → 29 taken 8 times.
✗ Branch 28 → 40 not taken.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 40 not taken.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 40 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 49 taken 1 time.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 34 not taken.
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 34 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 43 taken 1 time.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 6 → 7 taken 1266 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 1266 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 11 taken 1266 times.
✓ Branch 17 → 18 taken 205 times.
✗ Branch 17 → 34 not taken.
✓ Branch 25 → 26 taken 205 times.
✗ Branch 25 → 34 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 43 taken 205 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 34 not taken.
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 34 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 43 taken 1 time.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 6 → 7 taken 53 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 53 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 53 times.
✓ Branch 16 → 17 taken 35 times.
✗ Branch 16 → 33 not taken.
✓ Branch 24 → 25 taken 35 times.
✗ Branch 24 → 33 not taken.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 42 taken 35 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&):
✓ Branch 6 → 7 taken 48 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 48 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&):
✓ Branch 16 → 17 taken 20 times.
✓ Branch 16 → 32 taken 5 times.
✓ Branch 22 → 23 taken 20 times.
✗ Branch 22 → 32 not taken.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 41 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> const&):
✓ Branch 16 → 17 taken 20 times.
✓ Branch 16 → 32 taken 5 times.
✓ Branch 22 → 23 taken 20 times.
✗ Branch 22 → 32 not taken.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 41 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 2 → 3 taken 20 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 20 times.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 20 times.
✓ Branch 16 → 17 taken 20 times.
✓ Branch 16 → 32 taken 5 times.
✓ Branch 22 → 23 taken 20 times.
✗ Branch 22 → 32 not taken.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 41 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&):
✓ Branch 16 → 17 taken 20 times.
✓ Branch 16 → 32 taken 5 times.
✓ Branch 22 → 23 taken 20 times.
✗ Branch 22 → 32 not taken.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 41 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 40 not taken.
✓ Branch 31 → 32 taken 2 times.
✗ Branch 31 → 40 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 49 taken 2 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 6 → 7 taken 11 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 11 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 11 taken 11 times.
✓ Branch 20 → 21 taken 7 times.
✗ Branch 20 → 40 not taken.
✓ Branch 31 → 32 taken 7 times.
✗ Branch 31 → 40 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 49 taken 7 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 39 not taken.
✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 39 not taken.
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 48 taken 2 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 6 → 7 taken 1325940 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 1325940 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1325940 times.
✓ Branch 22 → 23 taken 132 times.
✗ Branch 22 → 45 not taken.
✓ Branch 33 → 34 taken 132 times.
✗ Branch 33 → 45 not taken.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 54 taken 132 times.
|
1328848 | if (prec == 0 || a.len() == 0 || b.len() == 0) { |
| 536 | ✗ | if constexpr (ea && eb) return cached<E, true>{}; | |
| 537 | 60 | else return trunc<E>(size_t(prec), T(0)); | |
| 538 | } | ||
| 539 | 1327870 | fft::transformed<E> ta_, tb_; | |
| 540 |
2/2auto ecnerwala::series::operator*<ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > >, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 52 → 55 taken 8 times.
auto ecnerwala::series::operator*<ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > >, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > >(ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&):
✓ Branch 58 → 61 taken 2 times.
|
1327870 | auto va = detail::product_operand(a, prec, ta_); |
| 541 |
5/5auto ecnerwala::series::operator*<ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > >, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > >(ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&):
✓ Branch 62 → 63 taken 2 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&):
✓ Branch 54 → 57 taken 8 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 13 → 14 taken 1266 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 9 → 10 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 13 → 14 taken 11 times.
|
1327870 | auto vb = detail::product_operand(b, prec, tb_); |
| 542 | if constexpr (ea && eb) { | ||
| 543 | 1326258 | std::vector<T> coeffs; | |
| 544 | 1326258 | fft::transformed<E> f; | |
| 545 |
4/4auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&):
✓ Branch 12 → 13 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 12 → 13 taken 53 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&):
✓ Branch 12 → 13 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 12 → 13 taken 1325940 times.
|
1326258 | auto ca = detail::as_cached_span(va, ta_), cb = detail::as_cached_span(vb, tb_); |
| 546 |
7/7auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&):
✓ Branch 12 → 13 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 12 → 13 taken 53 times.
✓ Branch 72 → 73 taken 35 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&):
✓ Branch 12 → 13 taken 48 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 78 → 79 taken 2 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 12 → 13 taken 1325940 times.
✓ Branch 84 → 85 taken 132 times.
|
1326427 | fft::multiply_cached<E>( |
| 547 | ca, ca.cache(), | ||
| 548 | cb, cb.cache(), | ||
| 549 | coeffs, f | ||
| 550 | ); | ||
| 551 | 1326934 | cached<E, true> w(exact<E>(std::move(coeffs))); | |
| 552 | 1326258 | w.cache() = std::move(f); | |
| 553 | 1326258 | return w; | |
| 554 | 1326644 | } else { | |
| 555 |
6/9auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 13 → 14 taken 1266 times.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1266 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 9 → 10 taken 20 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 13 → 14 taken 11 times.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 11 times.
|
2242 | trunc<E> r(size_t(prec), T(0)); |
| 556 |
3/6auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1266 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 11 times.
|
1612 | auto ca = detail::as_cached_span(va, ta_), cb = detail::as_cached_span(vb, tb_); |
| 557 |
16/16auto ecnerwala::series::operator*<ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > >, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 93 → 94 taken 8 times.
auto ecnerwala::series::operator*<ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > >, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > >(ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&):
✓ Branch 99 → 100 taken 2 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::prefix_cached<ecnerwala::fft::engines::ntt<modnum<998244353> > > const&):
✓ Branch 93 → 94 taken 8 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 93 → 94 taken 1 time.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 87 → 88 taken 1 time.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 16 → 17 taken 1266 times.
✓ Branch 87 → 88 taken 205 times.
auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 87 → 88 taken 1 time.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::crt<modnum<1000000007>, mod_goldilocks, modnum<2013265921> >, true> const&):
✓ Branch 85 → 86 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<mod_goldilocks>, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<mod_goldilocks>, true> const&):
✓ Branch 85 → 86 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 12 → 13 taken 20 times.
✓ Branch 85 → 86 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::split<modnum<1000000007> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::split<modnum<1000000007> >, true> const&):
✓ Branch 85 → 86 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 93 → 94 taken 2 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 16 → 17 taken 11 times.
✓ Branch 93 → 94 taken 7 times.
|
2242 | fft::multiply<E>( |
| 558 | ca, ca.cache(), | ||
| 559 | cb, cb.cache(), | ||
| 560 |
3/3auto ecnerwala::series::operator*<ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 16 → 17 taken 1266 times.
auto ecnerwala::series::operator*<ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false>, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> >(ecnerwala::series::span<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&, ecnerwala::series::cached_span<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&):
✓ Branch 12 → 13 taken 20 times.
auto ecnerwala::series::operator*<ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true>, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> >(ecnerwala::series::cached<ecnerwala::fft::engines::ntt<modnum<998244353> >, true> const&, ecnerwala::series::vec<ecnerwala::fft::engines::ntt<modnum<998244353> >, false> const&):
✓ Branch 16 → 17 taken 11 times.
|
1612 | std::span<T>(r) |
| 561 | ); | ||
| 562 | 1612 | return r; | |
| 563 | 1612 | } | |
| 564 | 1328382 | } | |
| 565 | |||
| 566 | // Wrapper around trunc which caches transform(s[:2^k]) for all k, | ||
| 567 | // matching the doubling shape of ps_inv/exp so they can populate the caches. | ||
| 568 | // TODO: make ps_inv/exp populate these | ||
| 569 | template <fft::engine E> | ||
| 570 | struct prefix_cached { | ||
| 571 | using T = typename E::value_type; | ||
| 572 | |||
| 573 | using engine_t = E; | ||
| 574 | static constexpr bool exact_v = false; | ||
| 575 | |||
| 576 | ✗ | prefix_cached() = default; | |
| 577 | // moving coefficients in or out is free: implicit on rvalues, explicit copy otherwise | ||
| 578 | ✗ | prefix_cached(trunc<E>&& s_) : s(std::move(s_)) {} | |
| 579 | 4 | explicit prefix_cached(const trunc<E>& s_) : s(s_) {} | |
| 580 | ✗ | operator trunc<E>() && { return std::move(s); } | |
| 581 | |||
| 582 |
4/8✓ Branch 31 → 32 taken 8 times.
✗ Branch 31 → 40 not taken.
✓ Branch 34 → 35 taken 2 times.
✗ Branch 34 → 46 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 49 taken 8 times.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 55 taken 2 times.
|
199 | int len() const { return s.len(); } |
| 583 | // unwrap to the owned coefficients | ||
| 584 | ✗ | const trunc<E>& uncached() const { return s; } | |
| 585 | ✗ | const T& operator[](int i) const { return s[size_t(i)]; } | |
| 586 | ✗ | auto begin() const { return s.cbegin(); } | |
| 587 | ✗ | auto end() const { return s.cend(); } | |
| 588 | ✗ | operator span<E, false>() const { return s; } | |
| 589 | |||
| 590 | // extend precision: appends coefficients, keeping all covering caches valid | ||
| 591 | 1 | void append(std::span<const T> tail) { | |
| 592 |
1/1✓ Branch 22 → 23 taken 1 time.
|
5 | s.insert(s.end(), tail.begin(), tail.end()); |
| 593 | 1 | } | |
| 594 | |||
| 595 | // The first k coefficients, with the covering prefix cache when one lines | ||
| 596 | // up with k (k a power of two, or k == len()); uncached otherwise. | ||
| 597 | 23 | maybe_cached<E, false> first(int k) const { | |
| 598 | 46 | assert(k <= len()); | |
| 599 | 23 | span<E, false> v = s.first(k); | |
| 600 | 23 | int n = nextPow2(k); | |
| 601 |
2/3✓ Branch 37 → 38 taken 23 times.
✗ Branch 37 → 41 not taken.
✓ Branch 39 → 40 taken 23 times.
|
46 | if (std::min(n, len()) == k) return {v, prefix_cache(n)}; |
| 602 | ✗ | return maybe_cached<E, false>(v); | |
| 603 | } | ||
| 604 | // the whole-sequence transform: the prefix cache covering all of len() | ||
| 605 | ✗ | fft::transformed<E>& cache() const { return prefix_cache(nextPow2(len())); } | |
| 606 | // cache over the prefix of length min(n, len()); n a power of two | ||
| 607 | 23 | fft::transformed<E>& prefix_cache(int n) const { | |
| 608 | 23 | assert(n > 0 && !(n & (n-1))); | |
| 609 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 23 times.
|
23 | int k = __builtin_ctz(unsigned(n)); |
| 610 |
2/2✓ Branch 11 → 12 taken 3 times.
✓ Branch 11 → 16 taken 20 times.
|
23 | if (k >= sz(caches)) caches.resize(size_t(k) + 1); |
| 611 | 23 | auto& c = caches[k]; | |
| 612 | 46 | int e = std::min(n, len()); | |
| 613 |
2/2✓ Branch 40 → 41 taken 8 times.
✓ Branch 40 → 84 taken 15 times.
|
23 | if (c.len != e) { |
| 614 |
1/1✓ Branch 50 → 51 taken 8 times.
|
24 | c.t = E::transform(s.first(e), 2 * n); |
| 615 | 8 | c.len = e; | |
| 616 | } | ||
| 617 | 23 | return c.t; | |
| 618 | } | ||
| 619 | |||
| 620 | private: | ||
| 621 | trunc<E> s; | ||
| 622 | // memoized transforms: logically const; len tracks how much of s each covers | ||
| 623 | 38 | struct entry { fft::transformed<E> t; int len = 0; }; | |
| 624 | mutable std::vector<entry> caches; | ||
| 625 | }; | ||
| 626 | |||
| 627 | /* namespace ecnerwala::series */ } | ||
| 628 |