1 module wafom.original;
2 
3 import digitalnet.implementation;
4 import std.algorithm, std.math, std.functional;
5 public import std.math : lg = log2;
6 
7 real WAFOM(U, Size)(DigitalNet!(U, Size) P, real c = 1, real exponent = 1)
8 {
9 	return (P + new U[P.dimensionR]).WAFOMimpl(getWAFOMMultiplicand(P.precision, c, exponent));
10 }
11 
12 real RMSWAFOM(U, Size)(DigitalNet!(U, Size) P, real c = 1)
13 {
14 	return (P + new U[P.dimensionR]).WAFOMimpl(getWAFOMMultiplicand(P.precision, c, 2));
15 }
16 
17 private class WAFOMMultiplicand
18 {
19 	real[2][] t;
20 	this (size_t n, real c, real exponent)
21 	{
22 		t = new real[2][n];
23 		foreach (j, ref u; t)
24 		{
25 			immutable eps = exp2(exponent * (c - 1 - (n - j)));
26 			u[0] = 1 + eps;
27 			u[1] = 1 - eps;
28 		}
29 	}
30 }
31 
32 auto _getWAFOMMultiplicand(size_t n, real c, real exponent)
33 {
34 	return new WAFOMMultiplicand(n, c, exponent);
35 }
36 
37 alias getWAFOMMultiplicand = memoize!_getWAFOMMultiplicand;
38 
39 private real WAFOMimpl(U, Size)(ShiftedDigitalNet!(U, Size) P, WAFOMMultiplicand wafomMultiplicand)
40 {
41 	if (P.bisectable)
42 	{
43 		auto Q = P.bisect;
44 		return (Q[0].WAFOMimpl(wafomMultiplicand) + Q[1].WAFOMimpl(wafomMultiplicand)) / 2;
45 	}
46 	real ret = 0;
47 	foreach (X; P)
48 	{
49 		real current = 1;
50 		foreach (x; X)
51 			foreach (j, u; wafomMultiplicand.t)
52 				current *= u[x >> j & 1];
53 		ret += current - 1;
54 	}
55 	return ret * exp2(-cast(ptrdiff_t)P.dimensionF2);
56 }