T6 = [(16347, .000000, .000000), (17395, .000000, .000017),
(18443, .000004, .001051), (18967, .000015, .005405),
(19491, .000051, .021317), (19595, .000062, .027153),
(19700, .000075, .034326), (19752, .000082, .038411),
(19805, .000090, .042970), (19857, .000098, .047852),
(19910, .000107, .053271), (20014, .000125, .065289),
(20538, .000235, .158591), (20800, .000292, .227754),
(21062, .000340, .310857), (21324, .000371, .404499),
(21586, .000381, .503536), (21848, .000367, .601928),
(22110, .000332, .693829), (22372, .000283, .774593),
(22634, .000227, .841425), (23158, .000122, .931859),
(23681, .000052, .975826), (24205, .000018, .992972),
(24729, .000005, .998325), (25777, .000000, .999947),
(26824, .000000, .999999), (29968, .000000, 1.000000)]
d6 = a6.density_df
t6 = pd.DataFrame([{'x': xx, 'agg probability': d6.loc[xx, 'p_total'],
'Table 6 probability': pp, 'agg CDF': d6.loc[xx, 'F'],
'Table 6 CDF': cc} for xx, pp, cc in T6])
t6['CDF diff'] = (t6['agg CDF'] - t6['Table 6 CDF']).abs()
GT(t6.set_index('x'),
formatters={'agg probability': 6, 'Table 6 probability': 6, 'agg CDF': 6,
'Table 6 CDF': 6, 'CDF diff': '{x:.2e}'})
6 Comments
6.1 The timing claim has not aged well
The paper’s case rests on operation counts and wall clock. Table 3 argues the FFT needs 6 to 41 times more real multiplications than direct thresholded convolution, and Table 4 shows the FFT taking 3,850 seconds at \(\lambda = 5004.8\) against 41 for the proposed method.
The multiplication count was never the right proxy, and the paper half says so: “the number of multiplications is only one of so many elements affecting the procedure’s processing time”. What it misses is the direction of the error. The authors count the FFT as \(O(N \log N)\) per convolution and then sum over 92,832 convolutions, because their formalization performs the convolutions one at a time, each an inverse transform of \(\phi_{n-1}\phi_1\). That is not how one computes a compound distribution with an FFT. The frequency enters through its probability generating function applied pointwise to the severity transform, so the whole compound distribution costs two transforms of length \(2^{23}\) regardless of whether \(\lambda\) is 500 or 91,000. Their equation (19) sums a per-convolution cost that a correct implementation never pays.
That is why the reproduction runs in seconds rather than hours, and why the ratio to their reported time is four orders of magnitude rather than the factor of 40 they anticipated in the other direction. Some of the gap is twenty years of hardware. The structural part is not.
6.2 What survives, and it is not nothing
The threshold idea is sound and
aggregateuses a version of it. Table 8 needed the frequency vector only out to \(n = 17\), because \(p(n)\) had fallen below \(10^{-14}\) by then, and that truncation is exactly the paper’s first phase. Their control, choosing the cutoff so that the retained mass and the first three moments are accurate to a stated tolerance, rather than by eye, is a good discipline and the closest thing in the paper to a genuinely portable idea.aggregate’s validation reports the analogous quantity as a moment comparison after the fact.The underflow point also survives. Panjer recursion really does fail at \(\lambda = 1004.8\) here while the transform does not, and that is a real structural difference between recursions that propagate a small \(g(0)\) and methods that do not. It just happens to be an argument for the FFT rather than against it.
6.3 The severity is the interesting part
The 14-point severity carries 45.6% of its mass at the single value 60 and another 9.9% at 55, so more than half the distribution sits on two atoms at the top of the range. That is what makes the case a fair stress test: the aggregate is a convolution of a very lumpy lattice law, and a method that smoothed it would show up immediately. Both the paper’s method and
aggregatereproduce the probability column, not just the CDF, which is the stronger test of the two.