40 static_assert(Field::kCharacteristicTwo);
43 static constexpr size_t kSubFieldBits = Field::kSubFieldBits;
45 explicit LCH14(
const Field &F) : f_(F) {
59 for (
size_t j = 0; j < kSubFieldBits; ++j) {
64 for (
size_t i = 0; i + 1 < kSubFieldBits; ++i) {
65 for (
size_t j = 0; j < kSubFieldBits; ++j) {
66 W[i + 1][j] = f_.mulf(W[i][j], f_.addf(W[i][j], W[i][i]));
71 for (
size_t i = 0; i < kSubFieldBits; ++i) {
72 Elt scale = f_.invertf(W[i][i]);
73 for (
size_t j = 0; j < kSubFieldBits; ++j) {
74 w_hat_[i][j] = f_.mulf(scale, W[i][j]);
81 Elt twiddle(
size_t i,
size_t u)
const {
83 for (
size_t k = 0; u != 0; ++k, u >>= 1) {
85 f_.add(t, w_hat_[i][k]);
92 void twiddles(
size_t i,
size_t l,
size_t coset, Elt tw[])
const {
93 tw[0] = twiddle(i, coset);
94 for (
size_t k = 0; (i + 1) + k < l; ++k) {
95 Elt shift = w_hat_[i][(i + 1) + k];
96 for (
size_t u = 0; u < (k1 << k); ++u) {
97 tw[u + (k1 << k)] = f_.addf(tw[u], shift);
102 size_t ntwiddles(
size_t l)
const {
return k1 << (l - 1); }
106 void FFT(
size_t l,
size_t coset, Elt B[])
const {
107 check(l <= kSubFieldBits,
"l <= kSubFieldBits");
111 std::vector<Elt> tw(ntwiddles(l));
113 for (
size_t i = l; i-- > 0;) {
115 twiddles(i, l, coset, &tw[0]);
116 for (
size_t u = 0; (u << (i + 1)) < (k1 << l); ++u) {
118 for (
size_t v = 0; v < s; ++v) {
119 butterfly_fwd(B, (u << (i + 1)) + v, s, twu);
126 void IFFT(
size_t l,
size_t coset, Elt B[])
const {
127 check(l <= kSubFieldBits,
"l <= kSubFieldBits");
131 std::vector<Elt> tw(ntwiddles(l));
133 for (
size_t i = 0; i < l; ++i) {
135 twiddles(i, l, coset, &tw[0]);
136 for (
size_t u = 0; (u << (i + 1)) < (k1 << l); ++u) {
138 for (
size_t v = 0; v < s; ++v) {
139 butterfly_bwd(B, (u << (i + 1)) + v, s, twu);
146 void BidirectionalFFT(
size_t l,
size_t k, Elt B[])
const {
147 check(l <= kSubFieldBits,
"l <= kSubFieldBits");
148 bidir_recur(l, 0, k, B);
152 Elt WHat_DEBUG(
size_t i,
size_t j)
const {
return w_hat_[i][j]; }
156 static constexpr size_t k1 = 1;
161 Elt w_hat_[kSubFieldBits][kSubFieldBits];
185 void bidir_recur(
size_t i,
size_t coset,
size_t k,
189 Elt twu = twiddle(i, coset);
192 for (
size_t uv = k; uv < s; ++uv) {
193 butterfly_fwd(B, uv, s, twu);
196 bidir_recur(i, coset, k, B);
198 for (
size_t uv = 0; uv < k; ++uv) {
199 butterfly_diag(B, uv, s, twu);
202 FFT(i, coset + s, B + s);
206 for (
size_t uv = k - s; uv < s; ++uv) {
207 butterfly_diag(B, uv, s, twu);
210 bidir_recur(i, coset + s, k - s, B + s);
212 for (
size_t uv = 0; uv < k - s; ++uv) {
213 butterfly_bwd(B, uv, s, twu);
219 inline void butterfly_fwd(Elt B[],
size_t uv,
size_t s,
220 const Elt &twu)
const {
221 f_.add(B[uv], f_.mulf(twu, B[uv + s]));
222 f_.add(B[uv + s], B[uv]);
225 inline void butterfly_bwd(Elt B[],
size_t uv,
size_t s,
226 const Elt &twu)
const {
227 f_.sub(B[uv + s], B[uv]);
228 f_.sub(B[uv], f_.mulf(twu, B[uv + s]));
232 inline void butterfly_diag(Elt B[],
size_t uv,
size_t s,
233 const Elt &twu)
const {
235 f_.add(B[uv + s], B[uv]);
236 f_.sub(B[uv], f_.mulf(twu, b1));