ParticipationAndSummary Summarize(Participation participation)
        {
            ParticipationAndSummary result = new ParticipationAndSummary();

            result.Participation = participation;

            ParticipationsSummary summary = new ParticipationsSummary();

            Correlator correlator = new Correlator();
            double     x          = this.GetWeight(participation.Duration);
            double     weight     = x / 2;

            correlator.Add(0, 0, weight);
            correlator.Add(x, x, weight);

            summary.Trend = correlator;

            Distribution logActiveTime = Distribution.MakeDistribution(Math.Log(participation.Duration.TotalSeconds), 0, 1);

            summary.LogActiveTime = logActiveTime;

            summary.Start = participation.StartDate;
            summary.End   = participation.EndDate;

            summary.CumulativeIntensity = participation.Duration;

            result.Summary = summary;


            return(result);
        }
        public ParticipationAndSummary Combine(ParticipationAndSummary a, ParticipationAndSummary b)
        {
            if (a == null || a.Summary.CumulativeIntensity.TotalSeconds <= 0)
            {
                return(b);
            }
            if (b == null || b.Summary.CumulativeIntensity.TotalSeconds <= 0)
            {
                return(a);
            }
            ParticipationsSummary earlier = a.Summary;
            ParticipationsSummary later   = b.Summary;

            if (earlier.Start.CompareTo(later.Start) > 0)
            {
                ParticipationsSummary temp = earlier;
                earlier = later;
                later   = temp;
            }

            ParticipationsSummary summary = new ParticipationsSummary();

            summary.CumulativeIntensity = earlier.CumulativeIntensity.Add(later.CumulativeIntensity);
            summary.Start         = earlier.Start;
            summary.End           = later.End;
            summary.LogActiveTime = earlier.LogActiveTime.Plus(later.LogActiveTime);

            // time between prev end and next start
            TimeSpan idleDuration = later.Start.Subtract(earlier.End);
            double   idleX1       = this.GetWeight(earlier.End.Subtract(earlier.Start));
            double   idleX2       = this.GetWeight(later.Start.Subtract(earlier.Start));

            double     earlierSum   = this.GetWeight(earlier.CumulativeIntensity);
            Correlator laterShifted = later.Trend.CopyAndShiftRightAndUp(idleX2, earlierSum);
            Correlator correlator   = earlier.Trend.Plus(laterShifted);

            if (idleDuration.TotalSeconds > 0)
            {
                double idleY  = earlierSum;
                double weight = this.GetWeight(idleDuration);
                correlator.Add(idleX1, idleY, weight);
                correlator.Add(idleX2, idleY, weight);
            }

            summary.Trend = correlator;


            ParticipationAndSummary result = new ParticipationAndSummary();

            result.Summary = summary;

            if (summary.Trend.Correlation < 0)
            {
                System.Diagnostics.Debug.WriteLine("illegal correlation found: " + summary.Trend.Correlation + " for Activity " + this.Owner.Name);
            }
            // not bothering to assign a Participation because nothing will need it

            return(result);
        }
        public ProgressionValue GetValueViaCorrelation(DateTime when, bool strictlyEarlier)
        {
            double   resultNumber = 0.5;
            DateTime startDate;
            // The UI for logging data improved at this date. Any earlier data isn't used for computing correlation
            DateTime changeDate = new DateTime(2015, 9, 20);

            if (when.CompareTo(changeDate) > 0)
            {
                startDate = changeDate;
            }
            else
            {
                startDate = DateTime.MinValue;
            }

            ParticipationAndSummary info = this.searchHelper.CombineBetweenKeys(startDate, true, when, !strictlyEarlier);

            if (info != null)
            {
                ParticipationsSummary summary = info.Summary;

                Correlator correlator = summary.Trend;

                double x          = this.GetWeight(when.Subtract(summary.Start));
                double predictedY = correlator.GetYForX(x);
                double actualY    = this.GetWeight(summary.CumulativeIntensity);
                double deltaY     = actualY - predictedY;
                // Ideally we'd just return deltaY, but we have to transform it into a predefined range so the interpolator can use it
                // Although it would be possible to divide by the total time elapsed, that would cause any deviation to decrease over time
                // So instead we just warp the space from (-infinity, infinity) into (0, 1)
                bool positive = true;
                if (deltaY < 0)
                {
                    deltaY  *= -1;
                    positive = false;
                }

                // rescale such that a 32 hour deviation reaches halfway to the end of the space
                resultNumber = deltaY / this.GetWeight(TimeSpan.FromHours(32));

                // rescale such that nothing escapes the end of the space
                resultNumber = 1.0 - 1.0 / (1.0 + Math.Log(1 + resultNumber));

                if (positive)
                {
                    resultNumber = (resultNumber + 1.0) / 2.0;
                }
                else
                {
                    resultNumber = (1 - resultNumber) / 2.0;
                }
            }
            return(new ProgressionValue(when, Distribution.MakeDistribution(resultNumber, 0, 0)));
        }
        public ParticipationsSummary SummarizeParticipationsBetween(DateTime startDate, DateTime endDate)
        {
            ParticipationAndSummary result = this.searchHelper.CombineBetweenKeys(startDate, true, endDate, false);

            if (result == null)
            {
                ParticipationsSummary summary = new ParticipationsSummary();
                summary.Start = startDate;
                summary.End   = endDate;
                summary.CumulativeIntensity = new TimeSpan();
                summary.LogActiveTime       = Distribution.Zero;
                summary.Trend = new Correlator();
                return(summary);
            }
            return(result.Summary);
        }