#region License Information
/* HeuristicLab
* Copyright (C) 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 .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using HEAL.Attic;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression.MultiObjective {
[Item("Multi Soft Constraints Evaluator",
"Calculates the Person R² and the constraints violations of a symbolic regression solution.")]
[StorableType("8E9D76B7-ED9C-43E7-9898-01FBD3633880")]
public class
SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator : SymbolicRegressionMultiObjectiveSplittingEvaluator {
#region Constructors
public SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator() { }
[StorableConstructor]
protected SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator(StorableConstructorFlag _) : base(_) { }
protected SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator(
SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator original, Cloner cloner) : base(original, cloner) { }
#endregion
public override IDeepCloneable Clone(Cloner cloner) {
return new SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator(this, cloner);
}
public override IOperation InstrumentedApply() {
var rows = GenerateRowsToEvaluate();
var solution = SymbolicExpressionTreeParameter.ActualValue;
var problemData = ProblemDataParameter.ActualValue;
var interpreter = SymbolicDataAnalysisTreeInterpreterParameter.ActualValue;
var estimationLimits = EstimationLimitsParameter.ActualValue;
var minIntervalWidth = MinSplittingWidth;
var maxIntervalSplitDepth = MaxSplittingDepth;
//var applyLinearScaling = ApplyLinearScalingParameter.ActualValue.Value;
var applyLinearScaling = false;
if (UseConstantOptimization)
SymbolicRegressionConstantOptimizationEvaluator.OptimizeConstants(interpreter, solution, problemData, rows,
applyLinearScaling,
ConstantOptimizationIterations,
ConstantOptimizationUpdateVariableWeights,
estimationLimits.Lower,
estimationLimits.Upper);
var qualities = Calculate(interpreter, solution, estimationLimits.Lower, estimationLimits.Upper, problemData,
rows, applyLinearScaling, DecimalPlaces, minIntervalWidth, maxIntervalSplitDepth);
QualitiesParameter.ActualValue = new DoubleArray(qualities);
return base.InstrumentedApply();
}
public override double[] Evaluate(IExecutionContext context, ISymbolicExpressionTree tree,
IRegressionProblemData problemData,
IEnumerable rows) {
SymbolicDataAnalysisTreeInterpreterParameter.ExecutionContext = context;
EstimationLimitsParameter.ExecutionContext = context;
ApplyLinearScalingParameter.ExecutionContext = context;
var quality = Calculate(SymbolicDataAnalysisTreeInterpreterParameter.ActualValue, tree,
EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper,
problemData, rows,
ApplyLinearScalingParameter.ActualValue.Value, DecimalPlaces, MinSplittingWidth,
MaxSplittingDepth);
SymbolicDataAnalysisTreeInterpreterParameter.ExecutionContext = null;
EstimationLimitsParameter.ExecutionContext = null;
ApplyLinearScalingParameter.ExecutionContext = null;
return quality;
}
public static double[] Calculate(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
ISymbolicExpressionTree solution, double lowerEstimationLimit,
double upperEstimationLimit,
IRegressionProblemData problemData, IEnumerable rows, bool applyLinearScaling,
int decimalPlaces, double minIntervalSplitWidth, int maxIntervalSplitDepth) {
OnlineCalculatorError errorState;
var estimatedValues =
interpreter.GetSymbolicExpressionTreeValues(solution, problemData.Dataset, rows);
var targetValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
double nmse;
var boundedEstimatedValues = estimatedValues.LimitToRange(lowerEstimationLimit, upperEstimationLimit);
nmse = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(targetValues, boundedEstimatedValues, out errorState);
if (errorState != OnlineCalculatorError.None) nmse = double.NaN;
if (nmse > 1)
nmse = 1;
var constraints = problemData.IntervalConstraints.Constraints.Where(c => c.Enabled);
var variableRanges = problemData.VariableRanges.GetReadonlyDictionary();
var objectives = new List {nmse};
var intervalInterpreter = new IntervalInterpreter();
/*{MinIntervalSplitWidth = minIntervalSplitWidth, MaxIntervalSplitDepth = maxIntervalSplitDetph};*/
var constraintObjectives = new List();
foreach (var c in constraints) {
var penalty = ConstraintExceeded(c, intervalInterpreter, variableRanges,
solution /*, problemData.IntervalSplitting*/);
var maxP = 0.1;
if (double.IsNaN(penalty) || double.IsInfinity(penalty) || penalty > maxP)
penalty = maxP;
constraintObjectives.Add(penalty);
}
objectives.AddRange(constraintObjectives);
return objectives.ToArray();
}
public static double ConstraintExceeded(IntervalConstraint constraint, IntervalInterpreter intervalInterpreter,
IReadOnlyDictionary variableRanges,
ISymbolicExpressionTree solution /*, bool splitting*/) {
if (constraint.Variable != null && !variableRanges.ContainsKey(constraint.Variable))
throw new ArgumentException(
$"The given variable {constraint.Variable} in the constraint does not exists in the model.",
nameof(IntervalConstraintsParser));
Interval resultInterval;
if (!constraint.IsDerivative) {
resultInterval =
intervalInterpreter.GetSymbolicExpressionTreeInterval(solution, variableRanges /*, splitting:splitting*/);
}
else {
var tree = solution;
for (var i = 0; i < constraint.NumberOfDerivations; ++i)
tree = DerivativeCalculator.Derive(tree, constraint.Variable);
resultInterval =
intervalInterpreter.GetSymbolicExpressionTreeInterval(tree, variableRanges /*, splitting: splitting*/);
}
//Calculate soft-constraints for intervals
if (constraint.Interval.Contains(resultInterval)) return 0;
var pLower = 0.0;
var pUpper = 0.0;
if (constraint.Interval.Contains(resultInterval.LowerBound))
pLower = 0;
else
pLower = constraint.Interval.LowerBound - resultInterval.LowerBound;
if (constraint.Interval.Contains(resultInterval.UpperBound))
pUpper = 0;
else
pUpper = resultInterval.UpperBound - constraint.Interval.UpperBound;
var penalty = Math.Abs(pLower) + Math.Abs(pUpper);
return penalty;
}
/*
* First objective is to maximize the Pearson R² value
* All following objectives have to be minimized ==> Constraints
*/
public override IEnumerable Maximization {
get {
var objectives = new List {false}; //First NMSE ==> min
objectives.AddRange(Enumerable.Repeat(false, 2)); //Constraints ==> min
return objectives;
}
}
}
}