Index: /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator.sln
===================================================================
--- /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator.sln	(revision 16135)
+++ /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator.sln	(revision 16135)
@@ -0,0 +1,22 @@
+﻿
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.OSGAEvaluator", "HeuristicLab.OSGAEvaluator\HeuristicLab.OSGAEvaluator.csproj", "{4148A27C-C6F5-44BA-9A57-1460F3758A24}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4148A27C-C6F5-44BA-9A57-1460F3758A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4148A27C-C6F5-44BA-9A57-1460F3758A24}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4148A27C-C6F5-44BA-9A57-1460F3758A24}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4148A27C-C6F5-44BA-9A57-1460F3758A24}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
Index: /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/AdjustedEvaluatedSolutionsAnalyzer.cs
===================================================================
--- /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/AdjustedEvaluatedSolutionsAnalyzer.cs	(revision 16135)
+++ /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/AdjustedEvaluatedSolutionsAnalyzer.cs	(revision 16135)
@@ -0,0 +1,76 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
+
+namespace HeuristicLab.OSGAEvaluator {
+  [Item("AdjustedEvaluatedSolutionsAnalyzer", "Analyzer which aggregates the adjusted evaluated solutions count from the predictive evaluator.")]
+  [StorableClass]
+  public class AdjustedEvaluatedSolutionsAnalyzer : SymbolicDataAnalysisSingleObjectiveAnalyzer {
+    private const string EvaluatorParameterName = "Evaluator";
+    private const string AdjustedEvaluatedSolutionsResultName = "AdjustedEvaluatedSolutions";
+
+    public ILookupParameter<SymbolicRegressionSingleObjectiveEvaluator> EvaluatorParameter {
+      get { return (ILookupParameter<SymbolicRegressionSingleObjectiveEvaluator>)Parameters[EvaluatorParameterName]; }
+    }
+
+    public SymbolicRegressionSingleObjectiveEvaluator Evaluator {
+      get { return EvaluatorParameter.ActualValue; }
+    }
+
+    public AdjustedEvaluatedSolutionsAnalyzer() {
+      Parameters.Add(new LookupParameter<SymbolicRegressionSingleObjectiveEvaluator>(EvaluatorParameterName));
+    }
+
+    [StorableConstructor]
+    protected AdjustedEvaluatedSolutionsAnalyzer(bool deserializing) : base(deserializing) { }
+
+    protected AdjustedEvaluatedSolutionsAnalyzer(AdjustedEvaluatedSolutionsAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AdjustedEvaluatedSolutionsAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var evaluator = Evaluator as SymbolicRegressionSingleObjectiveOsgaEvaluator;
+
+      if (evaluator == null)
+        return base.Apply();
+
+      var results = ResultCollectionParameter.ActualValue;
+      if (!results.ContainsKey(AdjustedEvaluatedSolutionsResultName)) {
+        results.Add(new Result(AdjustedEvaluatedSolutionsResultName, new DoubleValue(0)));
+      }
+      var adjustedEvaluatedSolutions = (DoubleValue)results[AdjustedEvaluatedSolutionsResultName].Value;
+      adjustedEvaluatedSolutions.Value += evaluator.AdjustedEvaluatedSolutions;
+      evaluator.AdjustedEvaluatedSolutions = 0;
+
+      return base.Apply();
+    }
+  }
+}
Index: /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator.csproj
===================================================================
--- /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator.csproj	(revision 16135)
+++ /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator.csproj	(revision 16135)
@@ -0,0 +1,136 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{4148A27C-C6F5-44BA-9A57-1460F3758A24}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.OSGAEvaluator</RootNamespace>
+    <AssemblyName>HeuristicLab.OSGAEvaluator</AssemblyName>
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="HeuristicLab.Analysis-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Analysis-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Core-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Data-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Operators-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Optimization-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Parameters-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Parameters-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Persistence-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AdjustedEvaluatedSolutionsAnalyzer.cs" />
+    <Compile Include="OSGAPredictionCountsAnalyzer.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SymbolicRegressionSingleObjectiveOSGAEvaluator.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
Index: /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/OSGAPredictionCountsAnalyzer.cs
===================================================================
--- /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/OSGAPredictionCountsAnalyzer.cs	(revision 16135)
+++ /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/OSGAPredictionCountsAnalyzer.cs	(revision 16135)
@@ -0,0 +1,111 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Linq;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
+
+namespace HeuristicLab.OSGAEvaluator {
+  [Item("OSGAPredictionCountsAnalyzer", "An analyzer which records the counts of the rejected offspring predicted by the evaluator without evaluating all rows.")]
+  [StorableClass]
+
+  public class OSGAPredictionCountsAnalyzer : SymbolicDataAnalysisSingleObjectiveAnalyzer {
+    private const string EvaluatorParameterName = "Evaluator";
+    private const string ResultCollectionParameterName = "Results";
+
+    public ILookupParameter<SymbolicRegressionSingleObjectiveEvaluator> EvaluatorParameter {
+      get { return (ILookupParameter<SymbolicRegressionSingleObjectiveEvaluator>)Parameters[EvaluatorParameterName]; }
+    }
+
+    public OSGAPredictionCountsAnalyzer() {
+      Parameters.Add(new LookupParameter<SymbolicRegressionSingleObjectiveEvaluator>(EvaluatorParameterName));
+    }
+
+    protected OSGAPredictionCountsAnalyzer(OSGAPredictionCountsAnalyzer original, Cloner cloner) : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OSGAPredictionCountsAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var evaluator = EvaluatorParameter.ActualValue as SymbolicRegressionSingleObjectiveOsgaEvaluator;
+      if (evaluator == null)
+        return base.Apply();
+
+      var rejectedStats = evaluator.RejectedStats;
+      var totalStats = evaluator.TotalStats;
+
+      if (rejectedStats.Rows == 0 || totalStats.Rows == 0)
+        return base.Apply();
+
+      ResultCollection predictionResults;
+      DataTable rejectedStatsTable, totalStatsTable, rejectedStatsPerGenerationTable;
+      if (!ResultCollection.ContainsKey("OS Prediction")) {
+        predictionResults = new ResultCollection();
+        rejectedStatsTable = new DataTable("Rejected Stats");
+        foreach (var rowName in rejectedStats.RowNames) {
+          rejectedStatsTable.Rows.Add(new DataRow(rowName) { VisualProperties = { StartIndexZero = true, ChartType = DataRowVisualProperties.DataRowChartType.Columns, LineWidth = 1 } });
+        }
+        predictionResults.Add(new Result("Rejected Stats", rejectedStatsTable));
+        totalStatsTable = new DataTable("Total Stats");
+        foreach (var rowName in totalStats.RowNames) {
+          totalStatsTable.Rows.Add(new DataRow(rowName) { VisualProperties = { StartIndexZero = true, ChartType = DataRowVisualProperties.DataRowChartType.Columns, LineWidth = 1 } });
+        }
+        predictionResults.Add(new Result("Total Stats", totalStatsTable));
+        rejectedStatsPerGenerationTable = new DataTable("Rejected Per Generation");
+        foreach (var rowName in rejectedStats.RowNames) {
+          rejectedStatsPerGenerationTable.Rows.Add(new DataRow(rowName) { VisualProperties = { StartIndexZero = true, ChartType = DataRowVisualProperties.DataRowChartType.Line, LineWidth = 1 } });
+          rejectedStatsPerGenerationTable.Rows[rowName].Values.Add(0d);
+        }
+        predictionResults.Add(new Result("Rejected Stats Per Generation", rejectedStatsPerGenerationTable));
+        ResultCollection.Add(new Result("OS Prediction", predictionResults));
+      } else {
+        predictionResults = (ResultCollection)ResultCollection["OS Prediction"].Value;
+        rejectedStatsTable = (DataTable)predictionResults["Rejected Stats"].Value;
+        totalStatsTable = (DataTable)predictionResults["Total Stats"].Value;
+        rejectedStatsPerGenerationTable = (DataTable)predictionResults["Rejected Stats Per Generation"].Value;
+      }
+
+      int i = 0;
+      foreach (var rowName in rejectedStats.RowNames) {
+        // pad values with a 0 on each side to prevent clipping
+        rejectedStatsTable.Rows[rowName].Values.Replace(new[] { 0d }.Concat(Enumerable.Range(0, rejectedStats.Columns).Select(j => (double)rejectedStats[i, j])).Concat(new[] { 0d }));
+        ++i;
+      }
+      i = 0;
+      foreach (var rowName in totalStats.RowNames) {
+        totalStatsTable.Rows[rowName].Values.Replace(new[] { 0d }.Concat(Enumerable.Range(0, totalStats.Columns).Select(j => (double)totalStats[i, j])).Concat(new[] { 0d }));
+        var row = rejectedStatsPerGenerationTable.Rows[rowName];
+        var sum = row.Values.Sum();
+        row.Values.Add(totalStats[i, 0] - sum);
+        ++i;
+      }
+      return base.Apply();
+    }
+  }
+}
Index: /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/Plugin.cs
===================================================================
--- /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/Plugin.cs	(revision 16135)
+++ /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/Plugin.cs	(revision 16135)
@@ -0,0 +1,8 @@
+﻿using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.OSGAEvaluator {
+  [Plugin("HeuristicLab.OSGAEvaluator", "OSGA Evaluator", "3.3.13.0")]
+  [PluginFile("HeuristicLab.OSGAEvaluator.dll", PluginFileType.Assembly)]
+  public class Plugin : PluginBase {
+  }
+}
Index: /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/SymbolicRegressionSingleObjectiveOSGAEvaluator.cs
===================================================================
--- /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/SymbolicRegressionSingleObjectiveOSGAEvaluator.cs	(revision 16135)
+++ /branches/2635_HeuristicLab.OSGAEvaluator/HeuristicLab.OSGAEvaluator/SymbolicRegressionSingleObjectiveOSGAEvaluator.cs	(revision 16135)
@@ -0,0 +1,406 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
+  [Item("SymbolicRegressionSingleObjectiveOSGAEvaluator", "An evaluator which tries to predict when a child will not be able to fullfil offspring selection criteria, to save evaluation time.")]
+  [StorableClass]
+  public class SymbolicRegressionSingleObjectiveOsgaEvaluator : SymbolicRegressionSingleObjectiveEvaluator {
+    private const string RelativeParentChildQualityThresholdParameterName = "RelativeParentChildQualityThreshold";
+    private const string RelativeFitnessEvaluationIntervalSizeParameterName = "RelativeFitnessEvaluationIntervalSize";
+    private const string ResultCollectionParameterName = "Results";
+    private const string AggregateStatisticsParameterName = "AggregateStatistics";
+    private const string ActualSelectionPressureParameterName = "SelectionPressure";
+    private const string UseAdaptiveQualityThresholdParameterName = "UseAdaptiveQualityThreshold";
+    private const string UseFixedEvaluationIntervalsParameterName = "UseFixedEvaluationIntervals";
+    private const string PreserveResultCompatibilityParameterName = "PreserveEvaluationResultCompatibility";
+
+    #region parameters
+    public IFixedValueParameter<BoolValue> PreserveResultCompatibilityParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[PreserveResultCompatibilityParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> UseFixedEvaluationIntervalsParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[UseFixedEvaluationIntervalsParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> UseAdaptiveQualityThresholdParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[UseAdaptiveQualityThresholdParameterName]; }
+    }
+    public ILookupParameter<DoubleValue> ActualSelectionPressureParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters[ActualSelectionPressureParameterName]; }
+    }
+    public ILookupParameter<ResultCollection> ResultCollectionParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters[ResultCollectionParameterName]; }
+    }
+    public IValueParameter<BoolValue> AggregateStatisticsParameter {
+      get { return (IValueParameter<BoolValue>)Parameters[AggregateStatisticsParameterName]; }
+    }
+    public IValueLookupParameter<DoubleValue> ComparisonFactorParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["ComparisonFactor"]; }
+    }
+    public IFixedValueParameter<PercentValue> RelativeParentChildQualityThresholdParameter {
+      get { return (IFixedValueParameter<PercentValue>)Parameters[RelativeParentChildQualityThresholdParameterName]; }
+    }
+    public IFixedValueParameter<PercentValue> RelativeFitnessEvaluationIntervalSizeParameter {
+      get { return (IFixedValueParameter<PercentValue>)Parameters[RelativeFitnessEvaluationIntervalSizeParameterName]; }
+    }
+    public IScopeTreeLookupParameter<DoubleValue> ParentQualitiesParameter { get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters["ParentQualities"]; } }
+    #endregion
+
+    #region parameter properties
+    public bool AggregateStatistics {
+      get { return AggregateStatisticsParameter.Value.Value; }
+      set { AggregateStatisticsParameter.Value.Value = value; }
+    }
+    public bool PreserveResultCompatibility {
+      get { return PreserveResultCompatibilityParameter.Value.Value; }
+      set { PreserveResultCompatibilityParameter.Value.Value = value; }
+    }
+    public bool UseFixedEvaluationIntervals {
+      get { return UseFixedEvaluationIntervalsParameter.Value.Value; }
+      set { UseFixedEvaluationIntervalsParameter.Value.Value = value; }
+    }
+    public bool UseAdaptiveQualityThreshold {
+      get { return UseAdaptiveQualityThresholdParameter.Value.Value; }
+      set { UseAdaptiveQualityThresholdParameter.Value.Value = value; }
+    }
+    public double RelativeParentChildQualityThreshold {
+      get { return RelativeParentChildQualityThresholdParameter.Value.Value; }
+      set { RelativeParentChildQualityThresholdParameter.Value.Value = value; }
+    }
+    public double RelativeFitnessEvaluationIntervalSize {
+      get { return RelativeFitnessEvaluationIntervalSizeParameter.Value.Value; }
+      set { RelativeFitnessEvaluationIntervalSizeParameter.Value.Value = value; }
+    }
+
+    #endregion
+
+    public override bool Maximization {
+      get { return true; }
+    }
+
+    // keep track of statistics
+    public double AdjustedEvaluatedSolutions { get; set; }
+    public IntMatrix RejectedStats { get; set; }
+    public IntMatrix TotalStats { get; set; }
+
+    public SymbolicRegressionSingleObjectiveOsgaEvaluator() {
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("ComparisonFactor", "Determines if the quality should be compared to the better parent (1.0), to the worse (0.0) or to any linearly interpolated value between them."));
+      Parameters.Add(new FixedValueParameter<PercentValue>(RelativeParentChildQualityThresholdParameterName, new PercentValue(0.9)));
+      Parameters.Add(new FixedValueParameter<PercentValue>(RelativeFitnessEvaluationIntervalSizeParameterName, new PercentValue(0.1)));
+      Parameters.Add(new LookupParameter<ResultCollection>(ResultCollectionParameterName));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("ParentQualities") { ActualName = "Quality" });
+      Parameters.Add(new ValueParameter<BoolValue>(AggregateStatisticsParameterName, new BoolValue(false)));
+      Parameters.Add(new LookupParameter<DoubleValue>(ActualSelectionPressureParameterName));
+      Parameters.Add(new FixedValueParameter<BoolValue>(UseAdaptiveQualityThresholdParameterName, new BoolValue(false)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(UseFixedEvaluationIntervalsParameterName, new BoolValue(false)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(PreserveResultCompatibilityParameterName, new BoolValue(false)));
+
+      RejectedStats = new IntMatrix();
+      TotalStats = new IntMatrix();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey(ActualSelectionPressureParameterName))
+        Parameters.Add(new LookupParameter<DoubleValue>(ActualSelectionPressureParameterName));
+
+      if (!Parameters.ContainsKey(UseAdaptiveQualityThresholdParameterName))
+        Parameters.Add(new FixedValueParameter<BoolValue>(UseAdaptiveQualityThresholdParameterName, new BoolValue(false)));
+
+      if (!Parameters.ContainsKey(UseFixedEvaluationIntervalsParameterName))
+        Parameters.Add(new FixedValueParameter<BoolValue>(UseFixedEvaluationIntervalsParameterName, new BoolValue(false)));
+
+      if (!Parameters.ContainsKey(PreserveResultCompatibilityParameterName))
+        Parameters.Add(new FixedValueParameter<BoolValue>(PreserveResultCompatibilityParameterName, new BoolValue(false)));
+    }
+
+    [StorableConstructor]
+    protected SymbolicRegressionSingleObjectiveOsgaEvaluator(bool deserializing) : base(deserializing) {
+      TotalStats = new IntMatrix();
+      RejectedStats = new IntMatrix();
+    }
+
+    protected SymbolicRegressionSingleObjectiveOsgaEvaluator(SymbolicRegressionSingleObjectiveOsgaEvaluator original,
+      Cloner cloner) : base(original, cloner) {
+      if (original.TotalStats != null)
+        TotalStats = cloner.Clone(original.TotalStats);
+
+      if (original.RejectedStats != null)
+        RejectedStats = cloner.Clone(original.RejectedStats);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicRegressionSingleObjectiveOsgaEvaluator(this, cloner);
+    }
+
+    public override void ClearState() {
+      base.ClearState();
+      RejectedStats = new IntMatrix();
+      TotalStats = new IntMatrix();
+      AdjustedEvaluatedSolutions = 0;
+    }
+
+    public override IOperation InstrumentedApply() {
+      var solution = SymbolicExpressionTreeParameter.ActualValue;
+      IEnumerable<int> rows = GenerateRowsToEvaluate();
+
+      var interpreter = SymbolicDataAnalysisTreeInterpreterParameter.ActualValue;
+      var estimationLimits = EstimationLimitsParameter.ActualValue;
+      var problemData = ProblemDataParameter.ActualValue;
+      var applyLinearScaling = ApplyLinearScalingParameter.ActualValue.Value;
+
+      double quality;
+      var parentQualities = ParentQualitiesParameter.ActualValue;
+
+      // parent subscopes are not present during evaluation of the initial population
+      if (parentQualities.Length > 0) {
+        quality = Calculate(interpreter, solution, estimationLimits, problemData, rows);
+      } else {
+        quality = Calculate(interpreter, solution, estimationLimits.Lower, estimationLimits.Upper, problemData, rows, applyLinearScaling);
+      }
+      QualityParameter.ActualValue = new DoubleValue(quality);
+
+      return base.InstrumentedApply();
+    }
+
+    public static double Calculate(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, ISymbolicExpressionTree solution, double lowerEstimationLimit, double upperEstimationLimit, IRegressionProblemData problemData, IEnumerable<int> rows, bool applyLinearScaling) {
+      IEnumerable<double> estimatedValues = interpreter.GetSymbolicExpressionTreeValues(solution, problemData.Dataset, rows);
+      IEnumerable<double> targetValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
+      OnlineCalculatorError errorState;
+
+      double r;
+      if (applyLinearScaling) {
+        var rCalculator = new OnlinePearsonsRCalculator();
+        CalculateWithScaling(targetValues, estimatedValues, lowerEstimationLimit, upperEstimationLimit, rCalculator, problemData.Dataset.Rows);
+        errorState = rCalculator.ErrorState;
+        r = rCalculator.R;
+      } else {
+        IEnumerable<double> boundedEstimatedValues = estimatedValues.LimitToRange(lowerEstimationLimit, upperEstimationLimit);
+        r = OnlinePearsonsRCalculator.Calculate(targetValues, boundedEstimatedValues, out errorState);
+      }
+      if (errorState != OnlineCalculatorError.None) return double.NaN;
+      return r * r;
+    }
+
+    private double Calculate(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, ISymbolicExpressionTree solution, DoubleLimit estimationLimits, IRegressionProblemData problemData, IEnumerable<int> rows) {
+      var lowerEstimationLimit = EstimationLimitsParameter.ActualValue.Lower;
+      var upperEstimationLimit = EstimationLimitsParameter.ActualValue.Upper;
+      var estimatedValues = interpreter.GetSymbolicExpressionTreeValues(solution, problemData.Dataset, rows).LimitToRange(lowerEstimationLimit, upperEstimationLimit);
+      var targetValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows).ToList();
+      var parentQualities = ParentQualitiesParameter.ActualValue.Select(x => x.Value);
+      var minQuality = double.MaxValue;
+      var maxQuality = double.MinValue;
+
+      foreach (var quality in parentQualities) {
+        if (minQuality > quality) minQuality = quality;
+        if (maxQuality < quality) maxQuality = quality;
+      }
+
+      var comparisonFactor = ComparisonFactorParameter.ActualValue.Value;
+      var parentQuality = minQuality + (maxQuality - minQuality) * comparisonFactor;
+
+      #region fixed intervals
+      if (UseFixedEvaluationIntervals) {
+        double threshold = parentQuality * RelativeParentChildQualityThreshold;
+
+        if (UseAdaptiveQualityThreshold) {
+          var actualSelectionPressure = ActualSelectionPressureParameter.ActualValue;
+          if (actualSelectionPressure != null)
+            threshold = parentQuality * (1 - actualSelectionPressure.Value / 100.0);
+        }
+
+        var estimatedEnumerator = estimatedValues.GetEnumerator();
+        var targetEnumerator = targetValues.GetEnumerator();
+
+        var rcalc = new OnlinePearsonsRCalculator();
+        var trainingPartitionSize = problemData.TrainingPartition.Size;
+        var interval = (int)Math.Floor(trainingPartitionSize * RelativeFitnessEvaluationIntervalSize);
+
+        var calculatedRows = 0;
+        #region aggregate statistics
+        if (AggregateStatistics) {
+          var trainingEnd = problemData.TrainingPartition.End;
+
+          double quality = 0;
+          int intervalCount = 0, rejectionInterval = 0;
+          var predictedRejected = false;
+
+          while (estimatedEnumerator.MoveNext() & targetEnumerator.MoveNext()) {
+            var estimated = estimatedEnumerator.Current;
+            var target = targetEnumerator.Current;
+            rcalc.Add(target, estimated);
+            ++calculatedRows;
+            if (calculatedRows % interval == 0 || calculatedRows == trainingPartitionSize) {
+              intervalCount++;
+              if (predictedRejected) continue;
+              var r = rcalc.ErrorState == OnlineCalculatorError.None ? rcalc.R : 0d;
+              quality = r * r;
+              if (!(quality > threshold)) {
+                rejectionInterval = intervalCount - 1;
+                predictedRejected = true;
+              }
+            }
+          }
+          var actualQuality = rcalc.ErrorState == OnlineCalculatorError.None ? rcalc.R : 0d;
+          actualQuality *= actualQuality;
+
+          if (!predictedRejected) quality = actualQuality;
+
+          var actuallyRejected = !(actualQuality > parentQuality);
+
+          if (RejectedStats.Rows == 0 || TotalStats.Rows == 0) {
+            RejectedStats = new IntMatrix(2, intervalCount + 1);
+            RejectedStats.RowNames = new[] { "Predicted", "Actual" };
+            RejectedStats.ColumnNames = Enumerable.Range(1, RejectedStats.Columns).Select(x => string.Format("0-{0}", Math.Min(trainingEnd, x * interval)));
+            TotalStats = new IntMatrix(2, 1);
+            TotalStats.RowNames = new[] { "Predicted", "Actual" };
+            TotalStats.ColumnNames = new[] { "Rejected" };
+          }
+
+          if (actuallyRejected) {
+            TotalStats[0, 0]++; // prediction true
+            TotalStats[1, 0]++;
+            RejectedStats[0, rejectionInterval]++;
+            RejectedStats[1, rejectionInterval]++;
+          } else {
+            if (predictedRejected) {
+              RejectedStats[0, rejectionInterval]++;
+              TotalStats[0, 0]++;
+            }
+          }
+          return quality;
+        }
+        #endregion
+        else {
+          while (estimatedEnumerator.MoveNext() & targetEnumerator.MoveNext()) {
+            rcalc.Add(targetEnumerator.Current, estimatedEnumerator.Current);
+            ++calculatedRows;
+            if (calculatedRows % interval == 0 || calculatedRows == trainingPartitionSize) {
+              var q = rcalc.ErrorState != OnlineCalculatorError.None ? double.NaN : rcalc.R;
+              var quality = q * q;
+              if (!(quality > threshold)) {
+                AdjustedEvaluatedSolutions += (double)calculatedRows / problemData.TrainingPartition.Size;
+                return quality;
+              }
+            }
+          }
+          var r = rcalc.ErrorState != OnlineCalculatorError.None ? double.NaN : rcalc.R;
+          var actualQuality = r * r;
+          AdjustedEvaluatedSolutions += 1d;
+          return actualQuality;
+        }
+        #endregion
+      } else {
+        var lsc = new OnlineLinearScalingParameterCalculator();
+        var rcalc = new OnlinePearsonsRCalculator();
+        var interval = (int)Math.Round(RelativeFitnessEvaluationIntervalSize * problemData.TrainingPartition.Size);
+        var quality = 0d;
+        var calculatedRows = 0;
+
+        var cache = PreserveResultCompatibility ? new List<double>(problemData.TrainingPartition.Size) : null;
+        foreach (var target in estimatedValues.Zip(targetValues, (e, t) => new { EstimatedValue = e, ActualValue = t })) {
+          if (cache != null)
+            cache.Add(target.EstimatedValue);
+
+          lsc.Add(target.EstimatedValue, target.ActualValue);
+          rcalc.Add(target.EstimatedValue, target.ActualValue);
+
+          calculatedRows++;
+
+          if (calculatedRows % interval != 0) continue;
+
+          var alpha = lsc.Alpha;
+          var beta = lsc.Beta;
+          if (lsc.ErrorState != OnlineCalculatorError.None) {
+            alpha = 0;
+            beta = 1;
+          }
+
+          var calc = (OnlinePearsonsRCalculator)rcalc.Clone();
+          foreach (var t in targetValues.Skip(calculatedRows)) {
+            var s = (t - alpha) / beta; // scaled target
+            calc.Add(s, t); // add pair (scaled, target) to the calculator
+          }
+          var r = calc.ErrorState == OnlineCalculatorError.None ? calc.R : 0d;
+          quality = r * r;
+
+          if (!(quality > parentQuality)) {
+            AdjustedEvaluatedSolutions += (double)calculatedRows / problemData.TrainingPartition.Size;
+            return quality;
+          }
+        }
+        if (PreserveResultCompatibility) {
+          // get quality for all the rows. to ensure reproducibility of results between this evaluator
+          // and the standard one, we calculate the quality in an identical way (otherwise the returned 
+          // quality could be slightly off due to rounding errors (in the range 1e-15 to 1e-16)
+          var applyLinearScaling = ApplyLinearScalingParameter.ActualValue.Value;
+          double r;
+          OnlineCalculatorError calculatorError;
+
+          if (applyLinearScaling) {
+            var alpha = lsc.Alpha;
+            var beta = lsc.Beta;
+            if (lsc.ErrorState != OnlineCalculatorError.None) {
+              alpha = 0;
+              beta = 1;
+            }
+            var boundedEstimatedValues = cache.Select(x => x * beta + alpha).LimitToRange(estimationLimits.Lower, estimationLimits.Upper);
+            r = OnlinePearsonsRCalculator.Calculate(boundedEstimatedValues, targetValues, out calculatorError);
+          } else {
+            var boundedEstimatedValues = cache.LimitToRange(estimationLimits.Lower, estimationLimits.Upper);
+            r = OnlinePearsonsRCalculator.Calculate(boundedEstimatedValues, targetValues, out calculatorError);
+          }
+          quality = calculatorError == OnlineCalculatorError.None ? r * r : 0d;
+        }
+        AdjustedEvaluatedSolutions += 1d;
+        return quality;
+      }
+    }
+
+    public override double Evaluate(IExecutionContext context, ISymbolicExpressionTree tree, IRegressionProblemData problemData, IEnumerable<int> rows) {
+      SymbolicDataAnalysisTreeInterpreterParameter.ExecutionContext = context;
+      EstimationLimitsParameter.ExecutionContext = context;
+      ApplyLinearScalingParameter.ExecutionContext = context;
+
+      var interpreter = SymbolicDataAnalysisTreeInterpreterParameter.ActualValue;
+      var estimationLimits = EstimationLimitsParameter.ActualValue;
+      var applyLinearScaling = ApplyLinearScalingParameter.ActualValue.Value;
+
+      double r2 = Calculate(interpreter, tree, estimationLimits.Lower, estimationLimits.Upper, problemData, rows, applyLinearScaling);
+
+      SymbolicDataAnalysisTreeInterpreterParameter.ExecutionContext = null;
+      EstimationLimitsParameter.ExecutionContext = null;
+      ApplyLinearScalingParameter.ExecutionContext = null;
+
+      return r2;
+    }
+  }
+}
