vd conv(vd a, vd b) { int s = max(sz(a),sz(b)), L = get(s), n = 1<<L; if (s <= 0) return {}; a.resize(n); a = fwht(a); b.resize(n); b = fwht(b); F0R(i,n) a[i] = a[i]*b[i]; a = fwht_rev(a); return a; }
/* * we expect correct parameter size and preallocated out. Last 3 parameters are * used as a cache - just supply the same vectors everytime when you're doing * this multiple times. */ void fwht_dyadic_multiply (const bvector& a, const bvector& b, bvector& out, std::vector<int>&t, std::vector<int>&A, std::vector<int>&B) { uint i; //lift everyting to Z. for (i = 0; i < a.size(); ++i) t[i] = a[i]; fwht (t, A); for (i = 0; i < b.size(); ++i) t[i] = b[i]; fwht (t, B); //multiply diagonals to A for (i = 0; i < A.size(); ++i) A[i] *= B[i]; fwht (A, t); uint bitpos = a.size(); //no problem as a.size() == 1<<m == 2^m for (i = 0; i < t.size(); ++i) out[i] = (t[i] & bitpos) ? 1 : 0; }
void mfwht(double data[], int *nrow, int *ncol){ for(int i=0; i < *ncol; i++){ fwht(data+(i * *nrow), nrow);} }
vd fwht_rev(vd& a) { vd res = fwht(a); F0R(i,sz(res)) res[i] /= a.size(); return res; }