Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/ShapeConstraint.cs

Last change on this file was 17995, checked in by dpiringe, 4 years ago

#3119

  • 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
File size: 8.0 KB
RevLine 
[17887]1#region License Information
2
3/* HeuristicLab
[17896]4 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[17887]5 *
6 * This file is part of HeuristicLab.
7 *
8 * HeuristicLab is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * HeuristicLab is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#endregion
23using System;
24using HEAL.Attic;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27
28namespace HeuristicLab.Problems.DataAnalysis {
29  [StorableType("8109BE58-CCFB-4462-A2F4-EEE5DFADAFF7")]
30  [Item("ShapeConstraint", "Constraint on the shape of a function e.g. monotonicity.")]
31  public sealed class ShapeConstraint : Item {
32    [Storable]
33    private string variable;
34
35    public string Variable {
36      get => variable;
[17937]37      set {
[17887]38        if (variable == value)
39          return;
40        variable = value;
[17896]41        OnToStringChanged();
[17887]42        OnChanged();
43      }
44    }
45
46    public bool IsDerivative => NumberOfDerivations > 0;
47
48    [Storable]
49    private int numberOfDerivations;
50
51    public int NumberOfDerivations {
52      get => numberOfDerivations;
53      set {
54        if (value < 0 || value > 3)
55          throw new ArgumentException("Number of derivation has to be between 0 - 3.");
56        if (numberOfDerivations == value)
57          return;
58        numberOfDerivations = value;
[17896]59        OnToStringChanged();
[17887]60        OnChanged();
61      }
62    }
63
64    [Storable]
65    private Interval interval;
66
67    public Interval Interval {
68      get => interval;
69      set {
70        if (interval == value)
71          return;
72        interval = value;
[17896]73        OnToStringChanged();
[17887]74        OnChanged();
75      }
76    }
77
78    [Storable]
79    private IntervalCollection regions;
80    public IntervalCollection Regions {
81      get => regions;
82      set {
83        if (regions != value) {
[17896]84          if (regions != null) regions.Changed -= regions_Changed;
[17887]85          regions = value;
[17896]86          if (regions != null) regions.Changed += regions_Changed;
87          OnToStringChanged();
[17887]88          OnChanged();
89        }
90      }
91    }
92
[17896]93
[17887]94    [Storable]
95    private double weight = 1.0;
96    public double Weight {
97      get => weight;
98      set {
[17900]99        if (weight <= 0.0) throw new ArgumentOutOfRangeException("Weight must be larger than zero.");
[17887]100        if (weight != value) {
101          weight = value;
[17896]102          OnToStringChanged();
[17887]103          OnChanged();
104        }
105      }
106    }
107
[17946]108    [Storable]
[17995]109    private Interval threshold = new Interval(0, 0);
[17946]110    public Interval Threshold {
111      get => threshold;
112      set {
113        if (threshold == value)
114          return;
115        threshold = value;
116        OnToStringChanged();
117        OnChanged();
118      }
119    }
120
[17995]121
122    [Storable]
123    private Interval targetInterval;
124    public Interval TargetInterval {
125      get => targetInterval;
126      set {
127        if (targetInterval == value)
128          return;
129        targetInterval = value;
130        OnToStringChanged();
131        OnChanged();
132      }
133    }
134
135    [Storable]
136    private Interval dynInterval = new Interval(double.NegativeInfinity, double.PositiveInfinity);
137    public Interval DynInterval {
138      get => dynInterval;
139      set {
140        if (dynInterval == value)
141          return;
142        dynInterval = value;
143        OnToStringChanged();
144        OnChanged();
145      }
146    }
147
[17887]148    [StorableConstructor]
149    private ShapeConstraint(StorableConstructorFlag _) : base(_) { }
150
[17896]151    [StorableHook(HookType.AfterDeserialization)]
152    private void AfterDeserialization() {
153      if (regions != null) regions.Changed += regions_Changed;
[17995]154      if (TargetInterval == null)
155        TargetInterval = new Interval(interval.LowerBound, interval.UpperBound);
[17896]156    }
157
[17887]158    // without derivation
[17995]159    public ShapeConstraint(Interval interval, double weight, Interval threshold, Interval dynInterval)
[17887]160      : this(string.Empty, 0,
[17995]161         interval, new IntervalCollection(), weight, threshold, dynInterval) { }
[17887]162
[17995]163    public ShapeConstraint(Interval interval, IntervalCollection regions, double weight, Interval threshold, Interval dynInterval)
[17887]164      : this(string.Empty, 0,
[17995]165         interval, regions, weight, threshold, dynInterval) { }
[17887]166
167    public ShapeConstraint(string variable, int numberOfDerivations,
[17995]168                              Interval interval, double weight, Interval threshold, Interval dynInterval)
[17887]169      : this(variable, numberOfDerivations,
[17995]170             interval, new IntervalCollection(), weight, threshold, dynInterval) { }
[17887]171
172    public ShapeConstraint(string variable, int numberOfDerivations,
[17995]173                              Interval interval, IntervalCollection regions, double weight, Interval threshold, Interval dynInterval) {
[17896]174      Variable = variable;
175      NumberOfDerivations = numberOfDerivations;
176      Interval = interval;
177      Regions = regions;
178      Weight = weight;
[17946]179      Threshold = threshold;
[17995]180      DynInterval = dynInterval;
181      TargetInterval = new Interval(interval.LowerBound, interval.UpperBound);
[17887]182    }
183
184    public override IDeepCloneable Clone(Cloner cloner) {
185      return new ShapeConstraint(this, cloner);
186    }
187
188    private ShapeConstraint(ShapeConstraint original, Cloner cloner)
189      : base(original, cloner) {
190      Variable = original.Variable;
191      NumberOfDerivations = original.NumberOfDerivations;
192      Interval = original.Interval;
[17896]193      Regions = cloner.Clone(original.Regions);
194      Weight = original.weight;
[17995]195      Threshold = original.Threshold;
196      DynInterval = original.DynInterval;
197      TargetInterval = original.TargetInterval;
[17887]198    }
199
200    public event EventHandler Changed;
201
202    private void OnChanged() {
203      var handlers = Changed;
204      if (handlers != null)
205        handlers(this, EventArgs.Empty);
206    }
207
208
[17896]209    private void regions_Changed(object sender, EventArgs e) {
210      OnToStringChanged();
211      OnChanged();
212    }
[17887]213
214    public override string ToString() {
215      return GenerateExpressionString();
216    }
217
218
219    private string GenerateExpressionString() {
220      string expression;
[17906]221      string write(double val) => double.IsPositiveInfinity(val) ? "inf." : double.IsNegativeInfinity(val) ? "-inf." : $"{val}";
[17887]222      if (!IsDerivative) {
[17995]223        expression = string.Format($"f in [{write(TargetInterval.LowerBound)} .. {write(TargetInterval.UpperBound)}]");
[17946]224      } else {
225        var derivationString = string.Empty;
226        switch (numberOfDerivations) {
227          case 1:
228            derivationString = ""; break;
229          case 2:
230            derivationString = "²"; break;
231          case 3:
232            derivationString = "³"; break;
[17887]233        }
[17995]234        expression = string.Format($"∂{derivationString}f/∂{Variable}{derivationString} in [{write(TargetInterval.LowerBound)} .. {write(TargetInterval.UpperBound)}]");
[17887]235      }
236
237      if (Regions != null) {
238        foreach (var region in Regions.GetReadonlyDictionary())
[17906]239          expression += $", {region.Key} in [{write(region.Value.LowerBound)} .. {write(region.Value.UpperBound)}]";
[17887]240      }
[17896]241      if (Weight != 1.0) {
[17891]242        expression += $" weight: {weight}";
243      }
[17995]244
[17946]245      if (!double.IsNegativeInfinity(Threshold.LowerBound) || !double.IsPositiveInfinity(Threshold.UpperBound))
[17995]246        expression += $" threshold in [{write(Threshold.LowerBound)} .. {write(Threshold.UpperBound)}]";
[17946]247
[17995]248      if (!double.IsNegativeInfinity(DynInterval.LowerBound) && !double.IsPositiveInfinity(DynInterval.UpperBound))
249        expression += $" start in [{write(DynInterval.LowerBound)} .. {write(DynInterval.UpperBound)}]";
250
[17887]251      return expression;
252    }
253  }
254}
Note: See TracBrowser for help on using the repository browser.