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