#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; } } } }