Windowed Component Fitter
Estimates each component from a window that reaches past its group into the neighbours, while leaving the assignment alone.
The method uses one set of intervals for two jobs: deciding which component an observation is attributed to, and deciding which data informs that component's estimate. This separates them. Assignment is unchanged — the same generators and refiners produce it, every observation still belongs to exactly one group, and the mixing weights are still the group proportions. Only the data behind each estimate widens.
The motivation is the truncation term of Proposition 2. A component estimated from a truncated slice of itself is being asked to match the slice rather than the component, and a narrow slice of almost anything looks flat. Widening the window shows the estimator more of the component's actual shape, at the cost of admitting more of its neighbours.
At a fraction of zero this is the wrapped fitter, exactly. Not approximately: the window computation short-circuits, so no arithmetic can separate the window from the group, and WindowEquivalenceTest checks that a whole experiment run through a zero-fraction wrapper reproduces the unwrapped one value for value.
Wrap this in the cache, not the other way round. The window is a pure function of the group's boundaries, the sample size and the fraction, so a cache keyed on the assignment range stays exactly correct and keeps its hit rate:
ComponentFitCache(WindowedComponentFitter(PDFComponentFitter(estimators), delta))
Wrapping the other way keys the cache on window ranges, which move whenever either edge does, and the hit rate falls for no benefit.
Parameters
the fitter that does the estimating
how far the window reaches into each neighbour, as a fraction of the group's own size. Zero reproduces the wrapped fitter.