#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;
using HeuristicLab.Parameters;
namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression.MultiObjective {
[Item("Multi Soft Constraints Evaluator",
"Calculates the NMSE and the constraints violations of a symbolic regression solution.")]
[StorableType("8E9D76B7-ED9C-43E7-9898-01FBD3633880")]
public class
SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator : SymbolicRegressionMultiObjectiveEvaluator
{
public const string DimensionsParameterName = "Dimensions";
private const string BoundsEstimatorParameterName = "Bounds estimator";
public IFixedValueParameter DimensionsParameter =>
(IFixedValueParameter) Parameters[DimensionsParameterName];
public IValueParameter BoundsEstimatorParameter =>
(IValueParameter) Parameters[BoundsEstimatorParameterName];
public IBoundsEstimator BoundsEstimator {
get => BoundsEstimatorParameter.Value;
set => BoundsEstimatorParameter.Value = value;
}
#region Constructors
public SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator() {
Parameters.Add(new FixedValueParameter(DimensionsParameterName, new IntValue(2)));
Parameters.Add(new ValueParameter(BoundsEstimatorParameterName, new IABoundsEstimator()));
}
[StorableConstructor]
protected SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator(StorableConstructorFlag _) : base(_) { }
protected SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator(
SymbolicRegressionMultiObjectiveMultiSoftConstraintEvaluator original, Cloner cloner) : base(original, cloner) { }
#endregion
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
if (!Parameters.ContainsKey(DimensionsParameterName))
Parameters.Add(new FixedValueParameter(DimensionsParameterName, new IntValue(2)));
if (!Parameters.ContainsKey(BoundsEstimatorParameterName))
Parameters.Add(new ValueParameter(BoundsEstimatorParameterName, new IABoundsEstimator()));
}
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 applyLinearScaling = ApplyLinearScalingParameter.ActualValue.Value;
if (UseConstantOptimization) {
SymbolicRegressionConstantOptimizationEvaluator.OptimizeConstants(interpreter, solution, problemData, rows,
false,
ConstantOptimizationIterations,
ConstantOptimizationUpdateVariableWeights,
estimationLimits.Lower,
estimationLimits.Upper);
} else {
if (applyLinearScaling) {
//Check for interval arithmetic grammar
//remove scaling nodes for linear scaling evaluation
var rootNode = new ProgramRootSymbol().CreateTreeNode();
var startNode = new StartSymbol().CreateTreeNode();
SymbolicExpressionTree newTree = null;
foreach (var node in solution.IterateNodesPrefix())
if (node.Symbol.Name == "Scaling") {
for (var i = 0; i < node.SubtreeCount; ++i) startNode.AddSubtree(node.GetSubtree(i));
rootNode.AddSubtree(startNode);
newTree = new SymbolicExpressionTree(rootNode);
break;
}
//calculate alpha and beta for scaling
var estimatedValues = interpreter.GetSymbolicExpressionTreeValues(newTree, problemData.Dataset, rows);
var targetValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
OnlineLinearScalingParameterCalculator.Calculate(estimatedValues, targetValues, out var alpha, out var beta,
out var errorState);
//Set alpha and beta to the scaling nodes from ia grammar
foreach (var node in solution.IterateNodesPrefix())
if (node.Symbol.Name == "Offset") {
node.RemoveSubtree(1);
var alphaNode = new ConstantTreeNode(new Constant()) {Value = alpha};
node.AddSubtree(alphaNode);
} else if (node.Symbol.Name == "Scaling") {
node.RemoveSubtree(1);
var betaNode = new ConstantTreeNode(new Constant()) {Value = beta};
node.AddSubtree(betaNode);
}
}
}
var qualities = Calculate(interpreter, solution, estimationLimits.Lower, estimationLimits.Upper, problemData,
rows, BoundsEstimator);
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, BoundsEstimator);
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, IBoundsEstimator estimator) {
OnlineCalculatorError errorState;
var estimatedValues = interpreter.GetSymbolicExpressionTreeValues(solution, problemData.Dataset, rows);
var targetValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
var constraints = problemData.IntervalConstraints.Constraints.Where(c => c.Enabled);
var intervalCollection = problemData.VariableRanges;
double nmse;
var boundedEstimatedValues = estimatedValues.LimitToRange(lowerEstimationLimit, upperEstimationLimit);
nmse = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(targetValues, boundedEstimatedValues, out errorState);
if (errorState != OnlineCalculatorError.None) nmse = 1.0;
if (nmse > 1)
nmse = 1.0;
var objectives = new List {nmse};
var results = IntervalUtil.IntervalConstraintsViolation(constraints, estimator, intervalCollection, solution);
foreach (var result in results) {
if (double.IsNaN(result) || double.IsInfinity(result)) {
objectives.Add(double.MaxValue);
} else {
objectives.Add(result);
}
}
return objectives.ToArray();
}
/*
* 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, DimensionsParameter.Value.Value)); //Constraints ==> min
return objectives;
}
}
}
}