public Interpolation(double input, AdaptiveInterpolation.Distribution output)
 {
     this.Input  = input;
     this.Output = output;
 }
        public Participation_BinComparison_View(Engine engine, IEnumerable <Activity> activitiesToPredictFrom, Activity activityToPredict, TimeSpan windowSize)
        {
            DateTime now = DateTime.Now;

            engine.EnsureRatingsAreAssociated();

            LinearProgression progressionToPredict = activityToPredict.ParticipationsSmoothed((new TimeSpan()).Subtract(windowSize));

            StatList <NeighborhoodInterpolation, Activity> results = new StatList <NeighborhoodInterpolation, Activity>(new Neighborhood_MiddleOutputMean_Comparer(), new NoopCombiner <Activity>());

            foreach (Activity activity in activitiesToPredictFrom)
            {
                System.Diagnostics.Debug.WriteLine("comparing " + activity + " and " + activityToPredict.Name);
                List <Datapoint> datapoints = activity.compareParticipations(windowSize, progressionToPredict, now.Subtract(windowSize));

                // put data into the interpolator
                FloatRange inputRange = new FloatRange(0, true, windowSize.TotalSeconds, true);
                AdaptiveLinearInterpolator <Distribution> interpolator = new AdaptiveLinearInterpolator <Distribution>(new HyperBox <Distribution>(new FloatRange[] { inputRange }), new DistributionAdder());
                foreach (Datapoint datapoint in datapoints)
                {
                    interpolator.AddDatapoint(new AdaptiveInterpolation.Datapoint <Distribution>(datapoint.Input, Distribution.MakeDistribution(datapoint.Output, 0, datapoint.Weight)));
                }

                // ask the interpolator which input has the highest average output
                IEnumerable <double[]> representativePoints = interpolator.FindRepresentativePoints();
                if (representativePoints.Count() > 0)
                {
                    double[] bestInput = new double[1];
                    AdaptiveInterpolation.Distribution bestOutput = null;
                    foreach (double[] coordinates in representativePoints)
                    {
                        AdaptiveInterpolation.Distribution output = interpolator.Interpolate(coordinates);
                        if (bestOutput == null || output.Mean > bestOutput.Mean)
                        {
                            bestInput  = coordinates;
                            bestOutput = output;
                        }
                    }

                    // Check nearby regions for their outputs too
                    HyperBox <Distribution> inputNeighborhood = interpolator.FindNeighborhoodCoordinates(bestInput);
                    double inputNeighborhoodWidth             = inputNeighborhood.Coordinates[0].Width;
                    double lowerInput  = Math.Max(inputNeighborhood.Coordinates[0].LowCoordinate - inputNeighborhoodWidth, inputRange.LowCoordinate);
                    double higherInput = Math.Min(inputNeighborhood.Coordinates[0].HighCoordinate + inputNeighborhoodWidth, inputRange.HighCoordinate);

                    NeighborhoodInterpolation result = new NeighborhoodInterpolation();
                    result.Middle = new Interpolation(bestInput[0], bestOutput);
                    result.Left   = new Interpolation(lowerInput, interpolator.Interpolate(new double[] { lowerInput }));
                    result.Right  = new Interpolation(higherInput, interpolator.Interpolate(new double[] { higherInput }));

                    results.Add(result, activity);
                }
            }

            IEnumerable <ListItemStats <NeighborhoodInterpolation, Activity> > resultList = results.AllItems;

            if (resultList.Count() <= 0)
            {
                // This shouldn't be able to happen unless we disallow predicting the activity from itself
                this.SubLayout = new TextblockLayout("No activities found!");
            }
            else
            {
                int numWindowDays = (int)windowSize.TotalDays;
                GridLayout_Builder layoutBuilder = new Vertical_GridLayout_Builder().Uniform();
                if (resultList.Count() > 1)
                {
                    string title = "Activities that when done most strongly predict future participations in " + activityToPredict.Name;
                    layoutBuilder.AddLayout(new TextblockLayout(title));
                }
                else
                {
                    string title = "Predicting future participations in " + activityToPredict.Name;
                    layoutBuilder.AddLayout(new TextblockLayout(title));
                }

                string explanation = "A block of the form a->{b,c,d} means that when you have spent an average of <a> min/day on the given activity over the last " + numWindowDays + " days, " +
                                     "you have spent on average <c> min/day on " + activityToPredict.Name + " over the next " + numWindowDays + " days, with <b> and <d> marking -1 and +1 standard deviation, respectively";
                layoutBuilder.AddLayout(new TextblockLayout(explanation));

                int count = 0;
                foreach (ListItemStats <NeighborhoodInterpolation, Activity> result in resultList.Reverse())
                {
                    count++;
                    if (count > 3)
                    {
                        break;
                    }
                    Activity activity = result.Value;
                    NeighborhoodInterpolation neighborhood = result.Key;
                    layoutBuilder.AddLayout(new TextblockLayout("After " + activity.Name + ":"));
                    foreach (Interpolation interpolation in neighborhood.Items)
                    {
                        double inputSecondsPerWindow = interpolation.Input;
                        double inputMinutesPerDay    = inputSecondsPerWindow / windowSize.TotalDays / 60;

                        double avgOutputSecondsPerWindow = interpolation.Output.Mean;
                        double avgOutputMinutesPerDay    = avgOutputSecondsPerWindow / windowSize.TotalDays / 60;

                        double stddevOutputSecondsPerWindow = interpolation.Output.StdDev;
                        double stddevOutputMinutesPerDay    = stddevOutputSecondsPerWindow / windowSize.TotalDays / 60;

                        string itemLine = Math.Round(inputMinutesPerDay, 1) + " -> {" +
                                          Math.Round((avgOutputMinutesPerDay - stddevOutputMinutesPerDay), 1) + "," +
                                          Math.Round(avgOutputMinutesPerDay, 1) + "," +
                                          Math.Round((avgOutputMinutesPerDay + stddevOutputMinutesPerDay), 1) + "}";
                        layoutBuilder.AddLayout(new TextblockLayout(itemLine));
                    }
                }

                this.SubLayout = layoutBuilder.Build();
            }
        }
 public AdaptiveInterpolation.Distribution ConvertToDistribution(Distribution distribution)
 {
     AdaptiveInterpolation.Distribution converted = new AdaptiveInterpolation.Distribution(distribution.SumValue, distribution.SumSquaredValue, distribution.Weight);
     return(converted);
 }