public override IOperation Apply()
        {
            DataTable        qualityDistribution = null;
            ResultCollection results             = ResultsParameter.ActualValue;
            string           description         = "Shows the quality distributions in the current population.";

            if (results.ContainsKey(HistogramName))
            {
                qualityDistribution = results[HistogramName].Value as DataTable;
            }
            else
            {
                qualityDistribution = new DataTable("Population Quality Distribution", description);
                qualityDistribution.VisualProperties.XAxisTitle = QualityParameter.ActualName;
                qualityDistribution.VisualProperties.YAxisTitle = "Frequency";
                results.Add(new Result(HistogramName, description, qualityDistribution));
            }
            DataRow row;

            if (!qualityDistribution.Rows.TryGetValue("QualityDistribution", out row))
            {
                row = new DataRow("QualityDistribution");
                row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Histogram;
                qualityDistribution.Rows.Add(row);
            }
            var qualities = QualityParameter.ActualValue;

            row.Values.Replace(qualities.Select(x => x.Value));

            if (StoreHistory)
            {
                string           historyResultName = HistogramName + " History";
                DataTableHistory qdHistory         = null;
                if (results.ContainsKey(historyResultName))
                {
                    qdHistory = results[historyResultName].Value as DataTableHistory;
                }
                else
                {
                    qdHistory = new DataTableHistory();
                    results.Add(new Result(historyResultName, qdHistory));
                }
                DataTable table     = (DataTable)qualityDistribution.Clone();
                IntValue  iteration = IterationsParameter.ActualValue;
                if (iteration != null)
                {
                    string iterationName = IterationsParameter.ActualName;
                    if (iterationName.EndsWith("s"))
                    {
                        iterationName = iterationName.Remove(iterationName.Length - 1);
                    }
                    string appendix = " at " + iterationName + " " + iteration.Value.ToString();
                    table.Name += appendix;
                    table.Rows["QualityDistribution"].VisualProperties.DisplayName += appendix;
                }
                qdHistory.Add(table);
            }
            return(base.Apply());
        }
    public override IOperation Apply() {
      UpdateCounter.Value++;
      // the analyzer runs periodically, every 'updateInterval' times
      if (UpdateCounter.Value == UpdateInterval.Value) {
        UpdateCounter.Value = 0; // reset counter

        // compute all tree lengths and store them in the lengthsTable
        var solutions = SymbolicExpressionTreeParameter.ActualValue;

        var treeLengthsTable = SymbolicExpressionTreeLengthsParameter.ActualValue;
        // if the table was not created yet, we create it here
        if (treeLengthsTable == null) {
          treeLengthsTable = new DataTable("Tree Length Histogram");
          SymbolicExpressionTreeLengthsParameter.ActualValue = treeLengthsTable;
        }

        // data table which stores tree length values
        DataRow treeLengthsTableRow;

        const string treeLengthsTableRowName = "Symbolic expression tree lengths";
        const string treeLengthsTableRowDesc = "The distribution of symbolic expression tree lengths";
        const string xAxisTitle = "Symbolic expression tree lengths";
        const string yAxisTitle = "Frequency / Number of tree individuals";

        var treeLengths = solutions.Select(s => (int)s.Length).ToList();

        int maxLength = treeLengths.Max(t => t);
        int minLength = treeLengths.Min(t => t);

        if (!treeLengthsTable.Rows.ContainsKey(treeLengthsTableRowName)) {
          treeLengthsTableRow = new DataRow(treeLengthsTableRowName, treeLengthsTableRowDesc, treeLengths.Select(x => (double)x));
          treeLengthsTable.Rows.Add(treeLengthsTableRow);
        } else {
          treeLengthsTableRow = treeLengthsTable.Rows[treeLengthsTableRowName];
          treeLengthsTableRow.Values.Replace(treeLengths.Select(x => (double)x));
        }

        double maximumAllowedTreeLength = MaximumSymbolicExpressionTreeLengthParameter.ActualValue.Value;

        treeLengthsTableRow.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Histogram;
        treeLengthsTableRow.VisualProperties.ExactBins = false;

        int range = maxLength - minLength;
        if (range == 0) range = 1;
        // the following trick should result in an integer intervalWidth of 1,2,4,...
        treeLengthsTableRow.VisualProperties.Bins = range;

        if (maxLength <= 25) // [0,25]
          treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0;
        else if (maxLength <= 100) // [26,100]
          treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0 / 2.0;
        else if (maxLength <= 250) // [101,250]
          treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0 / 5.0;
        else if (maxLength <= 500) // [251,500]
          treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0 / 10.0;
        else
          treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0 / 20.0; // [501,inf]

        treeLengthsTableRow.VisualProperties.IsVisibleInLegend = false;

        // visual properties for the X-axis
        treeLengthsTable.VisualProperties.XAxisMinimumAuto = false;
        treeLengthsTable.VisualProperties.XAxisMaximumAuto = false;
        treeLengthsTable.VisualProperties.XAxisMinimumFixedValue = 0.0;
        if (maxLength > maximumAllowedTreeLength + 1)
          treeLengthsTable.VisualProperties.XAxisMaximumFixedValue = maxLength + 1; // +1 so the histogram column for the maximum length won't get trimmed
        else
          treeLengthsTable.VisualProperties.XAxisMaximumFixedValue = maximumAllowedTreeLength + 1;
        treeLengthsTable.VisualProperties.XAxisTitle = xAxisTitle;
        //visual properties for the Y-axis
        treeLengthsTable.VisualProperties.YAxisMinimumAuto = false;
        treeLengthsTable.VisualProperties.YAxisMaximumAuto = false;
        treeLengthsTable.VisualProperties.YAxisMinimumFixedValue = 0.0;
        int maxFreq = (int)Math.Round(solutions.GroupBy(s => s.Length).Max(g => g.Count()) / treeLengthsTableRow.VisualProperties.ScaleFactor);
        if (maxFreq % 5 != 0)
          maxFreq += (5 - maxFreq % 5);
        double yAxisMaximumFixedValue = maxFreq;

        treeLengthsTable.VisualProperties.YAxisMaximumFixedValue = yAxisMaximumFixedValue;
        treeLengthsTable.VisualProperties.YAxisTitle = yAxisTitle;

        var results = ResultsParameter.ActualValue;

        if (!results.ContainsKey(treeLengthsTableRowName)) {
          results.Add(new Result(treeLengthsTableRowName, treeLengthsTable));
        } else {
          results[treeLengthsTableRowName].Value = treeLengthsTable;
        }

        bool storeHistory = StoreHistoryParameter.Value.Value;
        const string treeLengthHistoryTableName = "Tree lengths history";

        if (storeHistory) {
          var treeLengthsHistory = SymbolicExpressionTreeLengthsHistoryParameter.ActualValue;
          if (treeLengthsHistory == null) {
            treeLengthsHistory = new DataTableHistory();
            SymbolicExpressionTreeLengthsHistoryParameter.ActualValue = treeLengthsHistory;
          }
          treeLengthsHistory.Add((DataTable)treeLengthsTable.Clone());

          if (!results.ContainsKey(treeLengthHistoryTableName)) {
            results.Add(new Result(treeLengthHistoryTableName, treeLengthsHistory));
          } else {
            results[treeLengthHistoryTableName].Value = treeLengthsHistory;
          }
        }
      }
      return base.Apply();
    }
    public override IOperation Apply() {
      int updateInterval = UpdateIntervalParameter.Value.Value;
      IntValue updateCounter = UpdateCounterParameter.ActualValue;
      // if counter does not yet exist then initialize it with update interval
      // to make sure the solutions are analyzed on the first application of this operator
      if (updateCounter == null) {
        updateCounter = new IntValue(updateInterval);
        UpdateCounterParameter.ActualValue = updateCounter;
      } else updateCounter.Value++;

      //analyze solutions only every 'updateInterval' times
      if (updateCounter.Value == updateInterval) {
        updateCounter.Value = 0;

        bool max = MaximizationParameter.ActualValue.Value;
        ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
        bool storeHistory = StoreHistoryParameter.Value.Value;
        int count = CurrentScopeParameter.ActualValue.SubScopes.Count;

        if (count > 1) {
          // calculate solution similarities
          var similarityMatrix = SimilarityCalculator.CalculateSolutionCrowdSimilarity(CurrentScopeParameter.ActualValue);

          // sort similarities by quality
          double[][] sortedSimilarityMatrix = null;
          if (max)
            sortedSimilarityMatrix = similarityMatrix
              .Select((x, index) => new { Solutions = x, Quality = qualities[index] })
              .OrderByDescending(x => x.Quality)
              .Select(x => x.Solutions)
              .ToArray();
          else
            sortedSimilarityMatrix = similarityMatrix
              .Select((x, index) => new { Solutions = x, Quality = qualities[index] })
              .OrderBy(x => x.Quality)
              .Select(x => x.Solutions)
              .ToArray();

          double[,] similarities = new double[similarityMatrix.Length, similarityMatrix[0].Length];
          for (int i = 0; i < similarityMatrix.Length; i++)
            for (int j = 0; j < similarityMatrix[0].Length; j++)
              similarities[i, j] = similarityMatrix[i][j];

          // calculate minimum, average and maximum similarities
          double similarity;
          double[] minSimilarities = new double[count];
          double[] avgSimilarities = new double[count];
          double[] maxSimilarities = new double[count];
          for (int i = 0; i < count; i++) {
            minSimilarities[i] = 1;
            avgSimilarities[i] = 0;
            maxSimilarities[i] = 0;
            for (int j = 0; j < count; j++) {
              if (i != j) {
                similarity = similarities[i, j];

                if ((similarity < 0) || (similarity > 1))
                  throw new InvalidOperationException("Solution similarities have to be in the interval [0;1].");

                if (minSimilarities[i] > similarity) minSimilarities[i] = similarity;
                avgSimilarities[i] += similarity;
                if (maxSimilarities[i] < similarity) maxSimilarities[i] = similarity;
              }
            }
            avgSimilarities[i] = avgSimilarities[i] / (count - 1);
          }
          double avgMinSimilarity = minSimilarities.Average();
          double avgAvgSimilarity = avgSimilarities.Average();
          double avgMaxSimilarity = maxSimilarities.Average();

          // fetch results collection
          ResultCollection results;
          if (!ResultsParameter.ActualValue.ContainsKey(Name + " Results")) {
            results = new ResultCollection();
            ResultsParameter.ActualValue.Add(new Result(Name + " Results", results));
          } else {
            results = (ResultCollection)ResultsParameter.ActualValue[Name + " Results"].Value;
          }

          // store similarities
          HeatMap similaritiesHeatMap = new HeatMap(similarities, "Solution Similarities", 0.0, 1.0);
          if (!results.ContainsKey("Solution Similarities"))
            results.Add(new Result("Solution Similarities", similaritiesHeatMap));
          else
            results["Solution Similarities"].Value = similaritiesHeatMap;

          // store similarities history
          if (storeHistory) {
            if (!results.ContainsKey("Solution Similarities History")) {
              HeatMapHistory history = new HeatMapHistory();
              history.Add(similaritiesHeatMap);
              results.Add(new Result("Solution Similarities History", history));
            } else {
              ((HeatMapHistory)results["Solution Similarities History"].Value).Add(similaritiesHeatMap);
            }
          }

          // store average minimum, average and maximum similarity
          if (!results.ContainsKey("Average Minimum Solution Similarity"))
            results.Add(new Result("Average Minimum Solution Similarity", new DoubleValue(avgMinSimilarity)));
          else
            ((DoubleValue)results["Average Minimum Solution Similarity"].Value).Value = avgMinSimilarity;

          if (!results.ContainsKey("Average Average Solution Similarity"))
            results.Add(new Result("Average Average Solution Similarity", new DoubleValue(avgAvgSimilarity)));
          else
            ((DoubleValue)results["Average Average Solution Similarity"].Value).Value = avgAvgSimilarity;

          if (!results.ContainsKey("Average Maximum Solution Similarity"))
            results.Add(new Result("Average Maximum Solution Similarity", new DoubleValue(avgMaxSimilarity)));
          else
            ((DoubleValue)results["Average Maximum Solution Similarity"].Value).Value = avgMaxSimilarity;

          // store average minimum, average and maximum solution similarity data table
          DataTable minAvgMaxSimilarityDataTable;
          if (!results.ContainsKey("Average Minimum/Average/Maximum Solution Similarity")) {
            minAvgMaxSimilarityDataTable = new DataTable("Average Minimum/Average/Maximum Solution Similarity");
            minAvgMaxSimilarityDataTable.VisualProperties.XAxisTitle = "Iteration";
            minAvgMaxSimilarityDataTable.VisualProperties.YAxisTitle = "Solution Similarity";
            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Minimum Solution Similarity", null));
            minAvgMaxSimilarityDataTable.Rows["Average Minimum Solution Similarity"].VisualProperties.StartIndexZero = true;
            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Average Solution Similarity", null));
            minAvgMaxSimilarityDataTable.Rows["Average Average Solution Similarity"].VisualProperties.StartIndexZero = true;
            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Maximum Solution Similarity", null));
            minAvgMaxSimilarityDataTable.Rows["Average Maximum Solution Similarity"].VisualProperties.StartIndexZero = true;
            results.Add(new Result("Average Minimum/Average/Maximum Solution Similarity", minAvgMaxSimilarityDataTable));
          } else {
            minAvgMaxSimilarityDataTable = (DataTable)results["Average Minimum/Average/Maximum Solution Similarity"].Value;
          }
          minAvgMaxSimilarityDataTable.Rows["Average Minimum Solution Similarity"].Values.Add(avgMinSimilarity);
          minAvgMaxSimilarityDataTable.Rows["Average Average Solution Similarity"].Values.Add(avgAvgSimilarity);
          minAvgMaxSimilarityDataTable.Rows["Average Maximum Solution Similarity"].Values.Add(avgMaxSimilarity);

          // store minimum, average, maximum similarities data table
          DataTable minAvgMaxSimilaritiesDataTable = new DataTable("Minimum/Average/Maximum Solution Similarities");
          minAvgMaxSimilaritiesDataTable.VisualProperties.XAxisTitle = "Solution Index";
          minAvgMaxSimilaritiesDataTable.VisualProperties.YAxisTitle = "Solution Similarity";
          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Minimum Solution Similarity", null, minSimilarities));
          minAvgMaxSimilaritiesDataTable.Rows["Minimum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Average Solution Similarity", null, avgSimilarities));
          minAvgMaxSimilaritiesDataTable.Rows["Average Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Maximum Solution Similarity", null, maxSimilarities));
          minAvgMaxSimilaritiesDataTable.Rows["Maximum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
          if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities")) {
            results.Add(new Result("Minimum/Average/Maximum Solution Similarities", minAvgMaxSimilaritiesDataTable));
          } else {
            results["Minimum/Average/Maximum Solution Similarities"].Value = minAvgMaxSimilaritiesDataTable;
          }

          // store minimum, average, maximum similarities history
          if (storeHistory) {
            if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities History")) {
              DataTableHistory history = new DataTableHistory();
              history.Add(minAvgMaxSimilaritiesDataTable);
              results.Add(new Result("Minimum/Average/Maximum Solution Similarities History", history));
            } else {
              ((DataTableHistory)results["Minimum/Average/Maximum Solution Similarities History"].Value).Add(minAvgMaxSimilaritiesDataTable);
            }
          }
        }
      }
      return base.Apply();
    }
        public override IOperation Apply()
        {
            UpdateCounter.Value++;
            // the analyzer runs periodically, every 'updateInterval' times
            if (UpdateCounter.Value == UpdateInterval.Value)
            {
                UpdateCounter.Value = 0; // reset counter

                // compute all tree lengths and store them in the lengthsTable
                var solutions = SymbolicExpressionTreeParameter.ActualValue;

                var treeLengthsTable = SymbolicExpressionTreeLengthsParameter.ActualValue;
                // if the table was not created yet, we create it here
                if (treeLengthsTable == null)
                {
                    treeLengthsTable = new DataTable("Tree Length Histogram");
                    SymbolicExpressionTreeLengthsParameter.ActualValue = treeLengthsTable;
                }

                // data table which stores tree length values
                DataRow treeLengthsTableRow;

                const string treeLengthsTableRowName = "Symbolic expression tree lengths";
                const string treeLengthsTableRowDesc = "The distribution of symbolic expression tree lengths";
                const string xAxisTitle = "Symbolic expression tree lengths";
                const string yAxisTitle = "Frequency / Number of tree individuals";

                var treeLengths = solutions.Select(s => (int)s.Length).ToList();

                int maxLength = treeLengths.Max(t => t);
                int minLength = treeLengths.Min(t => t);

                if (!treeLengthsTable.Rows.ContainsKey(treeLengthsTableRowName))
                {
                    treeLengthsTableRow = new DataRow(treeLengthsTableRowName, treeLengthsTableRowDesc, treeLengths.Select(x => (double)x));
                    treeLengthsTable.Rows.Add(treeLengthsTableRow);
                }
                else
                {
                    treeLengthsTableRow = treeLengthsTable.Rows[treeLengthsTableRowName];
                    treeLengthsTableRow.Values.Replace(treeLengths.Select(x => (double)x));
                }

                double maximumAllowedTreeLength = MaximumSymbolicExpressionTreeLengthParameter.ActualValue.Value;

                treeLengthsTableRow.VisualProperties.ChartType       = DataRowVisualProperties.DataRowChartType.Histogram;
                treeLengthsTable.VisualProperties.HistogramExactBins = false;

                int range = maxLength - minLength;
                if (range == 0)
                {
                    range = 1;
                }
                // the following trick should result in an integer intervalWidth of 1,2,4,...
                treeLengthsTable.VisualProperties.HistogramBins = range;

                if (maxLength <= 25) // [0,25]
                {
                    treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0;
                }
                else if (maxLength <= 100) // [26,100]
                {
                    treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0 / 2.0;
                }
                else if (maxLength <= 250) // [101,250]
                {
                    treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0 / 5.0;
                }
                else if (maxLength <= 500) // [251,500]
                {
                    treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0 / 10.0;
                }
                else
                {
                    treeLengthsTableRow.VisualProperties.ScaleFactor = 1.0 / 20.0; // [501,inf]
                }
                treeLengthsTableRow.VisualProperties.IsVisibleInLegend = false;

                // visual properties for the X-axis
                treeLengthsTable.VisualProperties.XAxisMinimumAuto       = false;
                treeLengthsTable.VisualProperties.XAxisMaximumAuto       = false;
                treeLengthsTable.VisualProperties.XAxisMinimumFixedValue = 0.0;
                if (maxLength > maximumAllowedTreeLength + 1)
                {
                    treeLengthsTable.VisualProperties.XAxisMaximumFixedValue = maxLength + 1; // +1 so the histogram column for the maximum length won't get trimmed
                }
                else
                {
                    treeLengthsTable.VisualProperties.XAxisMaximumFixedValue = maximumAllowedTreeLength + 1;
                }
                treeLengthsTable.VisualProperties.XAxisTitle = xAxisTitle;
                //visual properties for the Y-axis
                treeLengthsTable.VisualProperties.YAxisMinimumAuto       = false;
                treeLengthsTable.VisualProperties.YAxisMaximumAuto       = false;
                treeLengthsTable.VisualProperties.YAxisMinimumFixedValue = 0.0;
                int maxFreq = (int)Math.Round(solutions.GroupBy(s => s.Length).Max(g => g.Count()) / treeLengthsTableRow.VisualProperties.ScaleFactor);
                if (maxFreq % 5 != 0)
                {
                    maxFreq += (5 - maxFreq % 5);
                }
                double yAxisMaximumFixedValue = maxFreq;

                treeLengthsTable.VisualProperties.YAxisMaximumFixedValue = yAxisMaximumFixedValue;
                treeLengthsTable.VisualProperties.YAxisTitle             = yAxisTitle;

                var results = ResultsParameter.ActualValue;

                if (!results.ContainsKey(treeLengthsTableRowName))
                {
                    results.Add(new Result(treeLengthsTableRowName, treeLengthsTable));
                }
                else
                {
                    results[treeLengthsTableRowName].Value = treeLengthsTable;
                }

                bool         storeHistory = StoreHistoryParameter.Value.Value;
                const string treeLengthHistoryTableName = "Tree lengths history";

                if (storeHistory)
                {
                    var treeLengthsHistory = SymbolicExpressionTreeLengthsHistoryParameter.ActualValue;
                    if (treeLengthsHistory == null)
                    {
                        treeLengthsHistory = new DataTableHistory();
                        SymbolicExpressionTreeLengthsHistoryParameter.ActualValue = treeLengthsHistory;
                    }
                    treeLengthsHistory.Add((DataTable)treeLengthsTable.Clone());

                    if (!results.ContainsKey(treeLengthHistoryTableName))
                    {
                        results.Add(new Result(treeLengthHistoryTableName, treeLengthsHistory));
                    }
                    else
                    {
                        results[treeLengthHistoryTableName].Value = treeLengthsHistory;
                    }
                }
            }
            return(base.Apply());
        }
    public override IOperation Apply() {
      DataTable qualityDistribution = null;
      ResultCollection results = ResultsParameter.ActualValue;
      string description = "Shows the quality distributions in the current population.";
      if (results.ContainsKey(HistogramName)) {
        qualityDistribution = results[HistogramName].Value as DataTable;
      } else {
        qualityDistribution = new DataTable("Population Quality Distribution", description);
        qualityDistribution.VisualProperties.XAxisTitle = QualityParameter.ActualName;
        qualityDistribution.VisualProperties.YAxisTitle = "Frequency";
        results.Add(new Result(HistogramName, description, qualityDistribution));
      }
      DataRow row;
      if (!qualityDistribution.Rows.TryGetValue("QualityDistribution", out row)) {
        row = new DataRow("QualityDistribution");
        row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Histogram;
        qualityDistribution.Rows.Add(row);
      }
      var qualities = QualityParameter.ActualValue;
      row.Values.Replace(qualities.Select(x => x.Value));

      if (StoreHistory) {
        string historyResultName = HistogramName + " History";
        DataTableHistory qdHistory = null;
        if (results.ContainsKey(historyResultName)) {
          qdHistory = results[historyResultName].Value as DataTableHistory;
        } else {
          qdHistory = new DataTableHistory();
          results.Add(new Result(historyResultName, qdHistory));
        }
        DataTable table = (DataTable)qualityDistribution.Clone();
        IntValue iteration = IterationsParameter.ActualValue;
        if (iteration != null) {
          string iterationName = IterationsParameter.ActualName;
          if (iterationName.EndsWith("s")) iterationName = iterationName.Remove(iterationName.Length - 1);
          string appendix = " at " + iterationName + " " + iteration.Value.ToString();
          table.Name += appendix;
          table.Rows["QualityDistribution"].VisualProperties.DisplayName += appendix;
        }
        qdHistory.Add(table);
      }
      return base.Apply();
    }