Index: /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionMetaModelAnalyzer.cs
===================================================================
--- /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionMetaModelAnalyzer.cs	(revision 17994)
+++ /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionMetaModelAnalyzer.cs	(revision 17994)
@@ -0,0 +1,113 @@
+﻿using HEAL.Attic;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
+  [StorableType("E5B7E058-E63F-4059-A87F-EA9247592254")]
+  public abstract class SymbolicRegressionMetaModelAnalyzer<T> 
+    : SymbolicDataAnalysisAnalyzer, ISymbolicExpressionTreeAnalyzer where T: class, IRegressionProblem {
+
+    #region constants
+    private const string ProblemsToAnalyzeParameterName = "Problems to Analyze";
+    private const string BaseProblemParameterName = "Base Problem";
+    private const string AnalyzeXIterationParameterName = "Analyze X Iteration";
+    #endregion
+
+    #region parameter properties
+    //IRegressionProblem
+    public IFixedValueParameter<ItemList<T>> ProblemsToAnalyzeParameter =>
+      (IFixedValueParameter<ItemList<T>>)Parameters[ProblemsToAnalyzeParameterName];
+
+    public IValueParameter<T> BaseProblemParameter =>
+      (IValueParameter<T>)Parameters[BaseProblemParameterName];
+
+    public IFixedValueParameter<IntValue> AnalyzeXIterationParameter =>
+      (IFixedValueParameter<IntValue>)Parameters[AnalyzeXIterationParameterName];
+    #endregion
+
+    public static int Iterations { get; set; } = 1;
+
+    #region constructors and cloning
+    protected SymbolicRegressionMetaModelAnalyzer(SymbolicRegressionMetaModelAnalyzer<T> original, Cloner cloner) :
+      base(original, cloner) { }
+
+    [StorableConstructor]
+    protected SymbolicRegressionMetaModelAnalyzer(StorableConstructorFlag _) : base(_) { }
+
+    public SymbolicRegressionMetaModelAnalyzer() {
+      Parameters.Add(new FixedValueParameter<ItemList<T>>(ProblemsToAnalyzeParameterName,
+        "List of datasets, which are used to find a meta model.", new ItemList<T>()));
+      Parameters.Add(new ValueParameter<T>(BaseProblemParameterName,
+        "The problem which uses the algorithm (just drag&drop it)."));
+      Parameters.Add(new FixedValueParameter<IntValue>(AnalyzeXIterationParameterName,
+        "After every X iteration, the analyzer will perform its step.", new IntValue(1)));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey(ProblemsToAnalyzeParameterName))
+        Parameters.Add(new FixedValueParameter<ItemList<T>>(ProblemsToAnalyzeParameterName,
+          "List of datasets, which are used to find a meta model.", new ItemList<T>()));
+
+      if (!Parameters.ContainsKey(BaseProblemParameterName))
+        Parameters.Add(new ValueParameter<T>(BaseProblemParameterName,
+          "The problem which uses the algorithm (just drag&drop it)."));
+
+      if (!Parameters.ContainsKey(AnalyzeXIterationParameterName))
+        Parameters.Add(new FixedValueParameter<IntValue>(AnalyzeXIterationParameterName,
+          "After every X iteration, the analyzer will perform its step.", new IntValue(1)));
+    }
+
+    #endregion
+
+    public override void InitializeState() {
+      Iterations = 1;
+      base.InitializeState();
+    }
+
+    public override void ClearState() {
+      Iterations = 1;
+      base.ClearState();
+    }
+
+    //protected abstract bool TryFittingSolution(ISymbolicExpressionTree tree, T problem, out SymbolicRegressionSolution solution);
+    protected abstract void PerformApply(T baseProblem, IEnumerable<T> problems, string targetVariable);
+
+    public override IOperation Apply() {
+      if (BaseProblemParameter.Value == null)
+        throw new ArgumentNullException("BaseProblemParameter",
+          "Base Problem Parameter is null! Please drag&drop the used problem into the parameter slot.");
+
+      if (Iterations >= AnalyzeXIterationParameter.Value.Value) {
+        Iterations = 1;
+        var baseProblem = BaseProblemParameter.Value;
+        var problems = ProblemsToAnalyzeParameter.Value;
+        var targetVariable = BaseProblemParameter.Value.ProblemData.TargetVariable;
+
+        // error handling
+        var badProblems = problems.Where(x => x.ProblemData.TargetVariable != targetVariable);
+        IList<Exception> errors = new List<Exception>();
+        foreach (var problem in badProblems)
+          errors.Add(new ArgumentException($"The target variable of the problem '{problem.Name}' does not match with the base problem."));
+        if (badProblems.Any())
+          throw new AggregateException(errors);
+
+        // apply
+        PerformApply(baseProblem, problems, targetVariable);
+      } else {
+        Iterations++;
+      }
+      return base.Apply();
+    }
+  }
+}
Index: /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSingleObjectiveMetaModelAnalyzer.cs
===================================================================
--- /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSingleObjectiveMetaModelAnalyzer.cs	(revision 17994)
+++ /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSingleObjectiveMetaModelAnalyzer.cs	(revision 17994)
@@ -0,0 +1,138 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HEAL.Attic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
+  [StorableType("4B69A82A-265B-46DA-9055-B6E0EB6C3EC8")]
+  public class SymbolicRegressionSingleObjectiveMetaModelAnalyzer 
+    : SymbolicRegressionMetaModelAnalyzer<SymbolicRegressionSingleObjectiveProblem>, ISymbolicExpressionTreeAnalyzer {
+
+    #region constants
+    private const string BestMetaModelParameterName = "Best Meta Model";
+    #endregion
+
+    #region parameter properties
+    public IResultParameter<ItemList<ISymbolicRegressionSolution>> BestMetaModelParameter =>
+      (IResultParameter<ItemList<ISymbolicRegressionSolution>>)Parameters[BestMetaModelParameterName];
+    #endregion
+
+    #region constructors and cloning
+    [StorableConstructor]
+    protected SymbolicRegressionSingleObjectiveMetaModelAnalyzer(StorableConstructorFlag _) : base(_) { }
+
+    protected SymbolicRegressionSingleObjectiveMetaModelAnalyzer(SymbolicRegressionSingleObjectiveMetaModelAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public SymbolicRegressionSingleObjectiveMetaModelAnalyzer() {
+      Parameters.Add(new ResultParameter<ItemList<ISymbolicRegressionSolution>>(BestMetaModelParameterName,
+        "A list with the meta model for all problems."));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Parameters.Remove(BestMetaModelParameterName);
+
+      if (!Parameters.ContainsKey(BestMetaModelParameterName))
+        Parameters.Add(new ResultParameter<ItemList<ISymbolicRegressionSolution>>(BestMetaModelParameterName,
+          "A list with all meta models for the problems."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) => new SymbolicRegressionSingleObjectiveMetaModelAnalyzer(this, cloner);
+    #endregion
+
+    protected override void PerformApply(
+      SymbolicRegressionSingleObjectiveProblem baseProblem, 
+      IEnumerable<SymbolicRegressionSingleObjectiveProblem> problems, 
+      string targetVariable) {
+      // init
+      var solutions = this.SymbolicExpressionTree.ToArray();
+      var bestQualityWithConstantOpt = baseProblem.Maximization.Value ? double.MinValue : double.MaxValue;
+      var bestQualityWithoutConstantOpt = baseProblem.Maximization.Value ? double.MinValue : double.MaxValue;
+      var evaluator = baseProblem.Evaluator;
+      var interpreter = baseProblem.SymbolicExpressionTreeInterpreter;
+      ISymbolicExpressionTree bestSolutionWithConstantOpt = null;
+      ISymbolicExpressionTree bestSolutionWithoutConstantOpt = null;
+      var metaModels = new ItemList<ISymbolicRegressionSolution>();
+      // iterate solutions
+      foreach (var solution in solutions) {
+        // calculate with constant optimization
+        var tmpSolution = (ISymbolicExpressionTree) solution.Clone();
+        double qualityAvg = CalculateAverageQuality(tmpSolution, evaluator, problems, interpreter, true);
+        // check if this solution is the best
+        bool isBest = baseProblem.Maximization.Value ? (bestQualityWithConstantOpt < qualityAvg) : (bestQualityWithConstantOpt > qualityAvg);
+        if (isBest) {
+          bestQualityWithConstantOpt = qualityAvg;
+          bestSolutionWithConstantOpt = tmpSolution;
+        }
+
+        // calculate it again without constant optimization to have a comparison
+        tmpSolution = (ISymbolicExpressionTree) solution.Clone();
+        qualityAvg = CalculateAverageQuality(tmpSolution, evaluator, problems, interpreter, false);
+        // check if this solution is the best
+        isBest = baseProblem.Maximization.Value ? (bestQualityWithoutConstantOpt < qualityAvg) : (bestQualityWithoutConstantOpt > qualityAvg);
+        if (isBest) {
+          bestQualityWithoutConstantOpt = qualityAvg;
+          bestSolutionWithoutConstantOpt = tmpSolution;
+        }
+      }
+
+      foreach(var problem in problems) {
+        metaModels.Add(BuildSolution(bestSolutionWithConstantOpt, targetVariable, problem, "withConstantOpt"));
+        metaModels.Add(BuildSolution(bestSolutionWithoutConstantOpt, targetVariable, problem, "withoutConstantOpt"));
+      }
+        
+      BestMetaModelParameter.ActualValue = metaModels;
+    }
+
+    private SymbolicRegressionSolution BuildSolution(
+      ISymbolicExpressionTree solution, 
+      string targetVariable,
+      SymbolicRegressionSingleObjectiveProblem problem,
+      string suffix) {
+      var model = new SymbolicRegressionModel(
+            targetVariable,
+            (ISymbolicExpressionTree)solution.Clone(),
+            new SymbolicDataAnalysisExpressionTreeInterpreter());
+      return new SymbolicRegressionSolution(model, problem.ProblemData) { Name = $"{problem.Name}_solution_{suffix}" };
+    }
+
+    private double CalculateAverageQuality(
+      ISymbolicExpressionTree solution,
+      ISymbolicDataAnalysisSingleObjectiveEvaluator<IRegressionProblemData> evaluator,
+      IEnumerable<SymbolicRegressionSingleObjectiveProblem> problems,
+      ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
+      bool useConstantOptimization) {
+      double qualitySum = 0.0;
+      // iterate problems
+      foreach (var problem in problems) {
+        var problemData = problem.ProblemData;
+
+        if (useConstantOptimization) {
+          SymbolicRegressionConstantOptimizationEvaluator.OptimizeConstants(
+            interpreter, 
+            solution, 
+            problemData, 
+            problemData.TrainingIndices,
+            false, 10, true);
+        }
+
+        qualitySum += evaluator.Evaluate(
+          ExecutionContext,
+          solution,
+          problemData,
+          problemData.TrainingIndices);
+      }
+        
+      // calculate the average quality
+      return qualitySum / problems.Count();
+    }
+  }
+}
