Skip to content

Commit 936726e

Browse files
committed
Added authors, a fuzz test, and interp
1 parent e3ff553 commit 936726e

File tree

2 files changed

+844
-8
lines changed

2 files changed

+844
-8
lines changed

content/numerical/FFTPolynomial.h

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Author: chilli
2+
* Author: chilli, Andrew He, Adamant
33
* Date: 2019-04-27
44
* Description: A FFT based Polynomial class.
55
*/
@@ -8,12 +8,13 @@
88
#include "../number-theory/ModularArithmetic.h"
99
#include "FastFourierTransform.h"
1010
#include "FastFourierTransformMod.h"
11+
// #include "NumberTheoreticTransform.h"
1112

1213
typedef Mod num;
1314
typedef vector<num> poly;
1415
vector<Mod> conv(vector<Mod> a, vector<Mod> b) {
15-
// auto res = convMod<mod>(vl(all(a)), vl(all(b)));
16-
auto res = conv(vl(all(a)), vl(all(b)));
16+
auto res = convMod<mod>(vl(all(a)), vl(all(b)));
17+
// auto res = conv(vl(all(a)), vl(all(b)));
1718
return vector<Mod>(all(res));
1819
}
1920
poly &operator+=(poly &a, const poly &b) {
@@ -39,12 +40,25 @@ poly operator*(poly a, const num b) {
3940
}
4041
OP(*, *=) OP(+, +=) OP(-, -=);
4142
poly modK(poly a, int k) { return {a.begin(), a.begin() + min(k, sz(a))}; }
43+
// Currently there's two of them - the second is the original one (simply following the formula), the first one is a version Adamant says is faster.
44+
// I haven't been able to replicate the difference in performance, however.
4245
poly inverse(poly A) {
4346
poly B = poly({num(1) / A[0]});
44-
while (sz(B) < sz(A))
45-
B = modK(B * (poly({num(2)}) - A * B), 2 * sz(B));
47+
while (sz(B) < sz(A)){
48+
poly C = B*modK(A, 2*sz(B));
49+
C = poly(C.begin()+sz(B), C.end());
50+
C = modK(B*C, sz(B));
51+
C.insert(C.begin(), sz(B), 0);
52+
B -= C;
53+
}
4654
return modK(B, sz(A));
4755
}
56+
// poly inverse(poly A) {
57+
// poly B = poly({num(1) / A[0]});
58+
// while (sz(B) < sz(A))
59+
// B = modK(B * (poly({num(2)}) - modK(A, 2*sz(B)) * B), 2 * sz(B));
60+
// return modK(B, sz(A));
61+
// }
4862
poly &operator/=(poly &a, poly b) {
4963
if (sz(a) < sz(b))
5064
return a = {};
@@ -73,10 +87,11 @@ poly deriv(poly a) {
7387
return b;
7488
}
7589
poly integr(poly a) {
76-
if (a.empty())
77-
return {0};
90+
if (a.empty()) return {0};
7891
poly b(sz(a) + 1);
79-
rep(i, 1, sz(b)) b[i] = a[i - 1] / num(i);
92+
b[1] = num(1);
93+
rep(i, 2, sz(b)) b[i] = b[mod%i]*Mod(-mod/i+mod);
94+
rep(i, 1 ,sz(b)) b[i] = a[i-1] * b[i];
8095
return b;
8196
}
8297
poly log(poly a) { return modK(integr(deriv(a) * inverse(a)), sz(a)); }
@@ -102,4 +117,33 @@ poly pow(poly a, ll m) {
102117
auto res = exp(log(a) * num(m)) * (j ^ m);
103118
res.insert(res.begin(), p*m, 0);
104119
return modK(res, n);
120+
}
121+
122+
vector<num> eval(const poly &a, const vector<num> &x) {
123+
int n = sz(x);
124+
if (!n) return {};
125+
vector<poly> up(2 * n);
126+
rep(i, 0, n) up[i + n] = poly({num(0) - x[i], 1});
127+
for (int i = n - 1; i > 0; i--)
128+
up[i] = up[2 * i] * up[2 * i + 1];
129+
vector<poly> down(2 * n);
130+
down[1] = a % up[1];
131+
rep(i, 2, 2 * n) down[i] = down[i / 2] % up[i];
132+
vector<num> y(n);
133+
rep(i, 0, n) y[i] = down[i + n][0];
134+
return y;
135+
}
136+
137+
poly interp(vector<num> x, vector<num> y) {
138+
int n = sz(x);
139+
vector<poly> up(n * 2);
140+
rep(i, 0, n) up[i + n] = poly({num(0) - x[i], num(1)});
141+
for (int i = n - 1; i > 0; i--)
142+
up[i] = up[2 * i] * up[2 * i + 1];
143+
vector<num> a = eval(deriv(up[1]), x);
144+
vector<poly> down(2 * n);
145+
rep(i, 0, n) down[i + n] = poly({y[i] * (num(1) / a[i])});
146+
for (int i = n - 1; i > 0; i--)
147+
down[i] = down[i * 2] * up[i * 2 + 1] + down[i * 2 + 1] * up[i * 2];
148+
return down[1];
105149
}

0 commit comments

Comments
 (0)