#region License Information /* HeuristicLab * Copyright (C) 2002-2018 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.Linq; using HeuristicLab.Analysis; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression { [StorableClass] public class SymbolicRegressionConstraintAnalyzer : SingleSuccessorOperator, IAnalyzer { private const string ResultCollectionParameterName = "Results"; private const string RegressionSolutionQualitiesResultName = "Constraint Violations"; public ILookupParameter ResultCollectionParameter { get { return (ILookupParameter)Parameters[ResultCollectionParameterName]; } } public virtual bool EnabledByDefault { get { return false; } } [StorableConstructor] protected SymbolicRegressionConstraintAnalyzer(bool deserializing) : base(deserializing) { } protected SymbolicRegressionConstraintAnalyzer(SymbolicRegressionConstraintAnalyzer original, Cloner cloner) : base(original, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new SymbolicRegressionConstraintAnalyzer(this, cloner); } public SymbolicRegressionConstraintAnalyzer() { Parameters.Add(new LookupParameter(ResultCollectionParameterName, "The result collection to store the analysis results.")); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { // BackwardsCompatibility3.3 } public override IOperation Apply() { var results = ResultCollectionParameter.ActualValue; IntervalConstraintsParser parser = new IntervalConstraintsParser(); var intervalInterpreter = new IntervalInterpreter(); if (!results.ContainsKey(RegressionSolutionQualitiesResultName)) { var newDataTable = new DataTable(RegressionSolutionQualitiesResultName); results.Add(new Result(RegressionSolutionQualitiesResultName, "Chart displaying the constraint violatoins.", newDataTable)); } var dataTable = (DataTable)results[RegressionSolutionQualitiesResultName].Value; foreach (var result in results.Where(r => r.Value is IRegressionSolution)) { var solution = (ISymbolicRegressionSolution)result.Value; var constraints = parser.Parse(((RegressionProblemData)solution.ProblemData).IntervalConstraintsParameter.Value.Value); var variableRanges = ((RegressionProblemData)solution.ProblemData).VariableRangesParameter.Value .VariableIntervals; if (dataTable.Rows.Count == 0) { foreach (var constraint in constraints) { if (!dataTable.Rows.ContainsKey(constraint.Derivaiton)) { dataTable.Rows.Add(new DataRow(constraint.Derivaiton)); } } } foreach (var constraint in constraints) { 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)); var numberOfViolations = dataTable.Rows[constraint.Derivaiton].Values.Count > 0 ? dataTable.Rows[constraint.Derivaiton].Values.Last() : 0; if (!constraint.IsDerivation) { var res = intervalInterpreter.GetSymbolicExressionTreeInterval(solution.Model.SymbolicExpressionTree, variableRanges); if (!IntervalInBoundaries(constraint.Interval, res, constraint.InclusiveLowerBound, constraint.InclusiveUpperBound)) { dataTable.Rows[constraint.Derivaiton].Values.Add(numberOfViolations + 1); } else { dataTable.Rows[constraint.Derivaiton].Values.Add(numberOfViolations); } } else { var tree = solution.Model.SymbolicExpressionTree; for (var i = 0; i < constraint.NumberOfDerivation; ++i) { tree = DerivativeCalculator.Derive(tree, constraint.Variable); } var res = intervalInterpreter.GetSymbolicExressionTreeInterval(solution.Model.SymbolicExpressionTree, variableRanges); if (!IntervalInBoundaries(constraint.Interval, res, constraint.InclusiveLowerBound, constraint.InclusiveUpperBound)) { dataTable.Rows[constraint.Derivaiton].Values.Add(numberOfViolations + 1); } else { dataTable.Rows[constraint.Derivaiton].Values.Add(numberOfViolations); } } } } return base.Apply(); } private static bool IntervalInBoundaries(Interval i1, Interval i2, bool inclusiveLower, bool inclusiveUpper) { if (double.IsNegativeInfinity(i1.LowerBound) && double.IsPositiveInfinity(i1.UpperBound)) return true; //Left-unbounded and right-bounded: if (double.IsNegativeInfinity(i1.LowerBound)) { if (inclusiveUpper) return i2.LowerBound <= i1.UpperBound && i2.UpperBound <= i1.UpperBound; return i2.LowerBound < i1.UpperBound && i2.UpperBound < i1.UpperBound; } //Left-bounded and right-unbounded: if (double.IsPositiveInfinity(i1.UpperBound)) { if (inclusiveLower) return i2.LowerBound >= i1.LowerBound && i2.UpperBound >= i1.LowerBound; return i2.LowerBound > i1.LowerBound && i2.UpperBound > i1.LowerBound; } //Proper and bounded: //Closed: if (inclusiveLower && inclusiveUpper) { return i1.LowerBound <= i2.LowerBound && i2.UpperBound <= i1.UpperBound; } //Open: if (!inclusiveLower && !inclusiveUpper) { return i1.LowerBound < i2.LowerBound && i2.UpperBound < i1.UpperBound; } //Left-closed, right-open: if (inclusiveLower) { return i1.LowerBound <= i2.LowerBound && i2.UpperBound < i1.UpperBound; } //Left-open, right-closed: return i1.LowerBound < i2.LowerBound && i2.UpperBound <= i1.UpperBound; } } }