public LinearProgression Shifted(TimeSpan offset)
        {
            LinearProgression shifted = new LinearProgression();

            foreach (ListItemStats <DateTime, double> stats in this.searchHelper.AllItems)
            {
                shifted.Add(stats.Key.Add(offset), stats.Value);
            }
            return(shifted);
        }
        public LinearProgression Smoothed(TimeSpan windowSize)
        {
            // make a List of the cumulative time spent
            DateTime minDate = this.Owner.DiscoveryDate;
            IEnumerable <ListItemStats <DateTime, ParticipationAndSummary> > items = this.searchHelper.AllItems;
            LinearProgression cumulatives = new LinearProgression();
            // first sort the starts and ends
            StatList <DateTime, double> deltaIntensities = new StatList <DateTime, double>(new DateComparer(), new FloatAdder());

            foreach (ListItemStats <DateTime, ParticipationAndSummary> item in items)
            {
                deltaIntensities.Add(item.Value.Participation.StartDate, 1);
                deltaIntensities.Add(item.Value.Participation.EndDate, -1);
            }
            if (deltaIntensities.NumItems < 1)
            {
                return(new LinearProgression());
            }
            DateTime maxDate = deltaIntensities.GetLastValue().Key;
            // now add up the (possibly overlapping) values
            double   intensity = 0;
            DateTime prevDate  = minDate;
            double   sum       = 0;

            foreach (ListItemStats <DateTime, double> deltaIntensity in deltaIntensities.AllItems)
            {
                double duration = deltaIntensity.Key.Subtract(prevDate).TotalSeconds;
                sum       += intensity * duration;
                intensity += deltaIntensity.Value;

                cumulatives.Add(deltaIntensity.Key, sum);
                prevDate = deltaIntensity.Key;
            }
            // find what's in the sliding window by subtracting the cumulative from the shifted cumulative
            LinearProgression shiftedCumulatives = cumulatives.Shifted(windowSize);

            if (windowSize.TotalSeconds > 0)
            {
                cumulatives.Add(maxDate.Add(windowSize), sum);
                LinearProgression result = cumulatives.Minus(shiftedCumulatives);
                return(result);
            }
            else
            {
                shiftedCumulatives.Add(maxDate, sum);
                LinearProgression result = shiftedCumulatives.Minus(cumulatives);
                return(result);
            }
        }
        public LinearProgression Minus(LinearProgression other)
        {
            StatList <DateTime, double> union = this.searchHelper.Union(other.searchHelper);
            LinearProgression           diff  = new LinearProgression();
            DateTime prevDate = new DateTime();

            foreach (ListItemStats <DateTime, double> item in union.AllItems)
            {
                DateTime when = item.Key;
                if (when == prevDate)
                {
                    // skip duplicates
                    continue;
                }
                // this relies on this.searchHelper.optimizeForLocality = true and other.searchHelper.optimizeForLocality = true for it to be fast
                double ourValue, theirValue;
                ourValue   = this.GetValueAt(when, false).Value.Mean;
                theirValue = other.GetValueAt(when, false).Value.Mean;
                double value = ourValue - theirValue;
                diff.Add(item.Key, value);
            }
            return(diff);
        }