Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
- added additional parameters to enable different evaluation options
- added additive restrictions
- added additional implementations for dynamic restrictions:
  - dynamic intervalls
  - exponatial smoothing
  - rising multiplier
- adapted `IntervalUtil` to get model bounds and refactored some sections
- adapted `ShapeConstraintsParser` for added features
- added a `ResultCollection` in `SymbolicRegressionSolution` for shape constraint violations

git-svn-id: https://src.heuristiclab.com/svn/core/branches/3119_AdditionalShapeConstraintFeatures@17995 2abd9481-f8db-48e9-bd25-06bc13291c1b
  • Loading branch information
DavidPiringer committed Jun 22, 2021
1 parent 6294fa5 commit 5bb4426
Show file tree
Hide file tree
Showing 7 changed files with 487 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
<Compile Include="SingleObjective\Evaluators\NMSEConstraintsEvaluator.cs" />
<Compile Include="SingleObjective\Evaluators\SymbolicRegressionMeanRelativeErrorEvaluator.cs" />
<Compile Include="SingleObjective\SymbolicRegressionSolutionsAnalyzer.cs" />
<Compile Include="SymbolicRegressionMetaModelAnalyzer.cs" />
<Compile Include="SymbolicRegressionPhenotypicDiversityAnalyzer.cs" />
<Compile Include="SymbolicRegressionPruningAnalyzer.cs" />
<Compile Include="SingleObjective\Evaluators\SymbolicRegressionLogResidualEvaluator.cs" />
Expand Down Expand Up @@ -157,6 +158,7 @@
<Compile Include="SingleObjective\Evaluators\SymbolicRegressionSingleObjectiveMeanSquaredErrorEvaluator.cs" />
<Compile Include="SingleObjective\Evaluators\SymbolicRegressionSingleObjectivePearsonRSquaredEvaluator.cs" />
<Compile Include="SymbolicRegressionPruningOperator.cs" />
<Compile Include="SymbolicRegressionSingleObjectiveMetaModelAnalyzer.cs" />
<Compile Include="SymbolicRegressionSolution.cs" />
<Compile Include="SymbolicRegressionSolutionImpactValuesCalculator.cs" />
<None Include="HeuristicLab.snk" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
[PluginDependency("HeuristicLab.Encodings.SymbolicExpressionTreeEncoding", "3.4")]
[PluginDependency("HeuristicLab.Operators", "3.3")]
[PluginDependency("HeuristicLab.Optimization", "3.3")]
[PluginDependency("HeuristicLab.Optimization.Operators", "3.3")]
[PluginDependency("HeuristicLab.Parameters", "3.3")]
[PluginDependency("HeuristicLab.Attic", "1.0")]
[PluginDependency("HeuristicLab.Problems.DataAnalysis", "3.4")]
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public sealed class SymbolicRegressionSolution : RegressionSolution, ISymbolicRe
private const string ModelLengthResultName = "Model Length";
private const string ModelDepthResultName = "Model Depth";

private const string ConstraintViolationsResultsResultName = "Constraint Violations Results";

private const string EstimationLimitsResultsResultName = "Estimation Limits Results";
private const string EstimationLimitsResultName = "Estimation Limits";
private const string TrainingUpperEstimationLimitHitsResultName = "Training Upper Estimation Limit Hits";
Expand Down Expand Up @@ -65,6 +67,10 @@ public int ModelDepth {
private set { ((IntValue)this[ModelDepthResultName].Value).Value = value; }
}

public ResultCollection ConstraintViolationsResults {
get { return (ResultCollection)this[ConstraintViolationsResultsResultName].Value; }
}

private ResultCollection EstimationLimitsResultCollection {
get { return (ResultCollection)this[EstimationLimitsResultsResultName].Value; }
}
Expand Down Expand Up @@ -136,6 +142,13 @@ public SymbolicRegressionSolution(ISymbolicRegressionModel model, IRegressionPro
estimationLimitResults.Add(new Result(TestNaNEvaluationsResultName, "", new IntValue()));
Add(new Result(EstimationLimitsResultsResultName, "Results concerning the estimation limits of symbolic regression solution", estimationLimitResults));


ResultCollection constraintViolationResults = new ResultCollection();
constraintViolationResults.Add(new Result("Violations", "Count of constraint violations", new IntValue()));
foreach (var constraint in problemData.ShapeConstraints.EnabledConstraints)
constraintViolationResults.Add(new Result(constraint.ToString(), "", new DoubleValue()));
Add(new Result(ConstraintViolationsResultsResultName, "Results concerning the constraint violations of symbolic regression solution", constraintViolationResults));

if (IntervalInterpreter.IsCompatible(Model.SymbolicExpressionTree))
Add(new Result(ModelBoundsResultName, "Results concerning the derivation of symbolic regression solution", new IntervalCollection()));

Expand All @@ -158,6 +171,7 @@ private void AfterDeserialization() {
estimationLimitResults.Add(new Result(TrainingNaNEvaluationsResultName, "", new IntValue()));
estimationLimitResults.Add(new Result(TestNaNEvaluationsResultName, "", new IntValue()));
Add(new Result(EstimationLimitsResultsResultName, "Results concerning the estimation limits of symbolic regression solution", estimationLimitResults));

CalculateResults();
}

Expand All @@ -178,6 +192,31 @@ private void CalculateResults() {
ModelLength = Model.SymbolicExpressionTree.Length;
ModelDepth = Model.SymbolicExpressionTree.Depth;

var constraints = ProblemData.ShapeConstraints.EnabledConstraints;
var estimator = new IntervalArithBoundsEstimator();
int violationCounter = 0;
foreach (var constraint in constraints) {
constraint.Interval = new Interval(constraint.TargetInterval.LowerBound, constraint.TargetInterval.UpperBound);
var v = IntervalUtil.GetConstraintViolation(constraint, estimator, ProblemData.VariableRanges, Model.SymbolicExpressionTree);
((DoubleValue)ConstraintViolationsResults[constraint.ToString()].Value).Value = v;
if(double.IsNaN(v) || double.IsInfinity(v) || v > 0) {
violationCounter++;
}
}
((IntValue)ConstraintViolationsResults["Violations"].Value).Value = violationCounter;


/*
if(constraints.Count() > 0)
ConstraintViolationsResults =
IntervalUtil.GetConstraintViolations(
constraints,
new IntervalArithBoundsEstimator(),
ProblemData.VariableRanges,
Model.SymbolicExpressionTree)
.Where(x => x > 0.0).Count();
*/

EstimationLimits.Lower = Model.LowerEstimationLimit;
EstimationLimits.Upper = Model.UpperEstimationLimit;

Expand Down
61 changes: 48 additions & 13 deletions HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/IntervalUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@

namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
public static class IntervalUtil {
public static IEnumerable<Interval> GetModelBounds(
IEnumerable<ShapeConstraint> constraints, IBoundsEstimator estimator, IntervalCollection intervalCollection,
ISymbolicExpressionTree solution) {
return constraints.Select(constraint => GetModelBound(constraint, estimator, intervalCollection, solution)).ToList();
}

public static Interval GetModelBound(
ShapeConstraint constraint, IBoundsEstimator estimator, IntervalCollection variableRanges,
ISymbolicExpressionTree tree) {
var regionRanges = GetRegionRanges(constraint, variableRanges);
tree = DeriveTree(tree, constraint, estimator);
return estimator.GetModelBound(tree, regionRanges);
}

public static IEnumerable<double> GetConstraintViolations(
IEnumerable<ShapeConstraint> constraints, IBoundsEstimator estimator, IntervalCollection intervalCollection,
ISymbolicExpressionTree solution) {
Expand All @@ -36,6 +50,39 @@ public static IEnumerable<double> GetConstraintViolations(
public static double GetConstraintViolation(
ShapeConstraint constraint, IBoundsEstimator estimator, IntervalCollection variableRanges,
ISymbolicExpressionTree tree) {

var regionRanges = GetRegionRanges(constraint, variableRanges);
tree = DeriveTree(tree, constraint, estimator);
return estimator.GetConstraintViolation(tree, regionRanges, constraint);
/*
if (!constraint.IsDerivative) {
return estimator.GetConstraintViolation(tree, regionRanges, constraint);
} else {
for (var i = 0; i < constraint.NumberOfDerivations; ++i) {
if (!estimator.IsCompatible(tree) || !DerivativeCalculator.IsCompatible(tree)) {
throw new ArgumentException("The tree contains an unsupported symbol.");
}
tree = DerivativeCalculator.Derive(tree, constraint.Variable);
}
return estimator.GetConstraintViolation(tree, regionRanges, constraint);
}
*/
}

private static ISymbolicExpressionTree DeriveTree(ISymbolicExpressionTree tree, ShapeConstraint constraint, IBoundsEstimator estimator) {
if (constraint.IsDerivative) {
for (var i = 0; i < constraint.NumberOfDerivations; ++i) {
if (!estimator.IsCompatible(tree) || !DerivativeCalculator.IsCompatible(tree))
throw new ArgumentException("The tree contains an unsupported symbol.");
tree = DerivativeCalculator.Derive(tree, constraint.Variable);
}
}
return tree;
}

private static IntervalCollection GetRegionRanges(ShapeConstraint constraint, IntervalCollection variableRanges) {
var varRanges = variableRanges.GetReadonlyDictionary();

if (!string.IsNullOrEmpty(constraint.Variable) && !varRanges.ContainsKey(constraint.Variable)) {
Expand All @@ -54,19 +101,7 @@ public static double GetConstraintViolation(
}
}

if (!constraint.IsDerivative) {
return estimator.GetConstraintViolation(tree, regionRanges, constraint);
} else {
for (var i = 0; i < constraint.NumberOfDerivations; ++i) {
if (!estimator.IsCompatible(tree) || !DerivativeCalculator.IsCompatible(tree)) {
throw new ArgumentException("The tree contains an unsupported symbol.");
}

tree = DerivativeCalculator.Derive(tree, constraint.Variable);
}

return estimator.GetConstraintViolation(tree, regionRanges, constraint);
}
return regionRanges;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public double Weight {
}

[Storable]
private Interval threshold;
private Interval threshold = new Interval(0, 0);
public Interval Threshold {
get => threshold;
set {
Expand All @@ -118,36 +118,67 @@ public Interval Threshold {
}
}


[Storable]
private Interval targetInterval;
public Interval TargetInterval {
get => targetInterval;
set {
if (targetInterval == value)
return;
targetInterval = value;
OnToStringChanged();
OnChanged();
}
}

[Storable]
private Interval dynInterval = new Interval(double.NegativeInfinity, double.PositiveInfinity);
public Interval DynInterval {
get => dynInterval;
set {
if (dynInterval == value)
return;
dynInterval = value;
OnToStringChanged();
OnChanged();
}
}

[StorableConstructor]
private ShapeConstraint(StorableConstructorFlag _) : base(_) { }

[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
if (regions != null) regions.Changed += regions_Changed;
if (TargetInterval == null)
TargetInterval = new Interval(interval.LowerBound, interval.UpperBound);
}

// without derivation
public ShapeConstraint(Interval interval, double weight, Interval threshold)
public ShapeConstraint(Interval interval, double weight, Interval threshold, Interval dynInterval)
: this(string.Empty, 0,
interval, new IntervalCollection(), weight, threshold) { }
interval, new IntervalCollection(), weight, threshold, dynInterval) { }

public ShapeConstraint(Interval interval, IntervalCollection regions, double weight, Interval threshold)
public ShapeConstraint(Interval interval, IntervalCollection regions, double weight, Interval threshold, Interval dynInterval)
: this(string.Empty, 0,
interval, regions, weight, threshold) { }
interval, regions, weight, threshold, dynInterval) { }

public ShapeConstraint(string variable, int numberOfDerivations,
Interval interval, double weight, Interval threshold)
Interval interval, double weight, Interval threshold, Interval dynInterval)
: this(variable, numberOfDerivations,
interval, new IntervalCollection(), weight, threshold) { }
interval, new IntervalCollection(), weight, threshold, dynInterval) { }

public ShapeConstraint(string variable, int numberOfDerivations,
Interval interval, IntervalCollection regions, double weight, Interval threshold) {
Interval interval, IntervalCollection regions, double weight, Interval threshold, Interval dynInterval) {
Variable = variable;
NumberOfDerivations = numberOfDerivations;
Interval = interval;
Regions = regions;
Weight = weight;
Threshold = threshold;
DynInterval = dynInterval;
TargetInterval = new Interval(interval.LowerBound, interval.UpperBound);
}

public override IDeepCloneable Clone(Cloner cloner) {
Expand All @@ -161,9 +192,11 @@ private ShapeConstraint(ShapeConstraint original, Cloner cloner)
Interval = original.Interval;
Regions = cloner.Clone(original.Regions);
Weight = original.weight;
Threshold = original.Threshold;
DynInterval = original.DynInterval;
TargetInterval = original.TargetInterval;
}


public event EventHandler Changed;

private void OnChanged() {
Expand All @@ -187,7 +220,7 @@ private string GenerateExpressionString() {
string expression;
string write(double val) => double.IsPositiveInfinity(val) ? "inf." : double.IsNegativeInfinity(val) ? "-inf." : $"{val}";
if (!IsDerivative) {
expression = string.Format($"f in [{write(Interval.LowerBound)} .. {write(Interval.UpperBound)}]");
expression = string.Format($"f in [{write(TargetInterval.LowerBound)} .. {write(TargetInterval.UpperBound)}]");
} else {
var derivationString = string.Empty;
switch (numberOfDerivations) {
Expand All @@ -198,7 +231,7 @@ private string GenerateExpressionString() {
case 3:
derivationString = "³"; break;
}
expression = string.Format($"∂{derivationString}f/∂{Variable}{derivationString} in [{write(Interval.LowerBound)} .. {write(Interval.UpperBound)}]");
expression = string.Format($"∂{derivationString}f/∂{Variable}{derivationString} in [{write(TargetInterval.LowerBound)} .. {write(TargetInterval.UpperBound)}]");
}

if (Regions != null) {
Expand All @@ -208,8 +241,12 @@ private string GenerateExpressionString() {
if (Weight != 1.0) {
expression += $" weight: {weight}";
}

if (!double.IsNegativeInfinity(Threshold.LowerBound) || !double.IsPositiveInfinity(Threshold.UpperBound))
expression += $" threshold: [{write(Threshold.LowerBound)} .. {write(Threshold.UpperBound)}]";
expression += $" threshold in [{write(Threshold.LowerBound)} .. {write(Threshold.UpperBound)}]";

if (!double.IsNegativeInfinity(DynInterval.LowerBound) && !double.IsPositiveInfinity(DynInterval.UpperBound))
expression += $" start in [{write(DynInterval.LowerBound)} .. {write(DynInterval.UpperBound)}]";

return expression;
}
Expand Down
Loading

0 comments on commit 5bb4426

Please sign in to comment.