Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3073_IA_constraint_splitting/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalInterpreter.cs @ 17628

Last change on this file since 17628 was 17628, checked in by chaider, 4 years ago

#3073

  • Added interval grammar for fixed scaling
  • Changed formatting
  • Fixed typos
File size: 13.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HEAL.Attic;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Data;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
30using HeuristicLab.Parameters;
31
32namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
33  [StorableType("DE6C1E1E-D7C1-4070-847E-63B68562B10C")]
34  [Item("IntervalInterpreter", "Intperter for calculation of intervals of symbolic models.")]
35  public sealed class IntervalInterpreter : ParameterizedNamedItem, IStatefulItem {
36
37    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
38
39    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter => (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName];
40
41    public int EvaluatedSolutions {
42      get => EvaluatedSolutionsParameter.Value.Value;
43      set => EvaluatedSolutionsParameter.Value.Value = value;
44    }
45
46    [StorableConstructor]
47    private IntervalInterpreter(StorableConstructorFlag _) : base(_) { }
48    private IntervalInterpreter(IntervalInterpreter original, Cloner cloner)
49        : base(original, cloner) { }
50
51    public IntervalInterpreter()
52        : base("IntervalInterpreter", "Intperter for calculation of intervals of symbolic models.") {
53      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
54    }
55
56    public override IDeepCloneable Clone(Cloner cloner) {
57      return new IntervalInterpreter(this, cloner);
58    }
59
60    private readonly object syncRoot = new object();
61
62    #region IStatefulItem Members
63    public void InitializeState() {
64      EvaluatedSolutions = 0;
65    }
66    public void ClearState() { }
67    #endregion
68
69    public Interval GetSymbolicExpressionTreeInterval(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable<int> rows = null) {
70      var variableRanges = DatasetUtil.GetVariableRanges(dataset, rows);
71      return GetSymbolicExpressionTreeInterval(tree, variableRanges);
72    }
73
74    public Interval GetSymbolicExpressionTreeIntervals(ISymbolicExpressionTree tree, IDataset dataset,
75      out IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals, IEnumerable<int> rows = null) {
76      var variableRanges = DatasetUtil.GetVariableRanges(dataset, rows);
77      return GetSymbolicExpressionTreeIntervals(tree, variableRanges, out nodeIntervals);
78    }
79
80    public Interval GetSymbolicExpressionTreeInterval(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
81      lock (syncRoot) {
82        EvaluatedSolutions++;
83      }
84      int instructionCount = 0;
85      var instructions = PrepareInterpreterState(tree, variableRanges);
86      var outputInterval = Evaluate(instructions, ref instructionCount);
87
88      // because of numerical errors the bounds might be incorrect
89      return outputInterval.LowerBound <= outputInterval.UpperBound ? outputInterval : new Interval(outputInterval.UpperBound, outputInterval.LowerBound);
90    }
91
92
93    public Interval GetSymbolicExpressionTreeIntervals(ISymbolicExpressionTree tree,
94      IReadOnlyDictionary<string, Interval> variableRanges, out IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals) {
95      lock (syncRoot) {
96        EvaluatedSolutions++;
97      }
98      int instructionCount = 0;
99      var intervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();
100      var instructions = PrepareInterpreterState(tree, variableRanges);
101      var outputInterval = Evaluate(instructions, ref instructionCount, intervals);
102
103      // fix incorrect intervals if necessary (could occur because of numerical errors)
104      nodeIntervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();
105      foreach (var kvp in intervals) {
106        var interval = kvp.Value;
107        if (interval.IsInfiniteOrUndefined || interval.LowerBound <= interval.UpperBound)
108          nodeIntervals.Add(kvp.Key, interval);
109        else
110          nodeIntervals.Add(kvp.Key, new Interval(interval.UpperBound, interval.LowerBound));
111      }
112
113      // because of numerical errors the bounds might be incorrect
114      if (outputInterval.IsInfiniteOrUndefined || outputInterval.LowerBound <= outputInterval.UpperBound)
115        return outputInterval;
116      else
117        return new Interval(outputInterval.UpperBound, outputInterval.LowerBound);
118    }
119
120
121    private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
122      if (variableRanges == null)
123        throw new ArgumentNullException("No variablew ranges are present!", nameof(variableRanges));
124
125      //Check if all variables used in the tree are present in the dataset
126      foreach (var variable in tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName).Distinct()) {
127        if (!variableRanges.ContainsKey(variable)) throw new InvalidOperationException($"No ranges for variable {variable} is present");
128      }
129
130      Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
131      foreach (Instruction instr in code.Where(i => i.opCode == OpCodes.Variable)) {
132        var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
133        instr.data = variableRanges[variableTreeNode.VariableName];
134      }
135      return code;
136    }
137
138    private Interval Evaluate(Instruction[] instructions, ref int instructionCounter, IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = null) {
139      Instruction currentInstr = instructions[instructionCounter];
140      //Use ref parameter, because the tree will be iterated through recursively from the left-side branch to the right side
141      //Update instructionCounter, whenever Evaluate is called
142      instructionCounter++;
143      Interval result = null;
144
145      switch (currentInstr.opCode) {
146        //Variables, Constants, ...
147        case OpCodes.Variable: {
148            var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
149            var weightInterval = new Interval(variableTreeNode.Weight, variableTreeNode.Weight);
150            var variableInterval = (Interval)currentInstr.data;
151
152            result = Interval.Multiply(variableInterval, weightInterval);
153            break;
154          }
155        case OpCodes.Constant: {
156            var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
157            result = new Interval(constTreeNode.Value, constTreeNode.Value);
158            break;
159          }
160        //Elementary arithmetic rules
161        case OpCodes.Add: {
162            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
163            for (int i = 1; i < currentInstr.nArguments; i++) {
164              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
165              result = Interval.Add(result, argumentInterval);
166            }
167            break;
168          }
169        case OpCodes.Sub: {
170            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
171            if (currentInstr.nArguments == 1)
172              result = Interval.Multiply(new Interval(-1, -1), result);
173
174            for (int i = 1; i < currentInstr.nArguments; i++) {
175              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
176              result = Interval.Subtract(result, argumentInterval);
177            }
178            break;
179          }
180        case OpCodes.Mul: {
181            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
182            for (int i = 1; i < currentInstr.nArguments; i++) {
183              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
184              result = Interval.Multiply(result, argumentInterval);
185            }
186            break;
187          }
188        case OpCodes.Div: {
189            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
190            if (currentInstr.nArguments == 1)
191              result = Interval.Divide(new Interval(1, 1), result);
192
193            for (int i = 1; i < currentInstr.nArguments; i++) {
194              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
195              result = Interval.Divide(result, argumentInterval);
196            }
197            break;
198          }
199        //Trigonometric functions
200        case OpCodes.Sin: {
201            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
202            result = Interval.Sine(argumentInterval);
203            break;
204          }
205        case OpCodes.Cos: {
206            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
207            result = Interval.Cosine(argumentInterval);
208            break;
209          }
210        case OpCodes.Tan: {
211            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
212            result = Interval.Tangens(argumentInterval);
213            break;
214          }
215        case OpCodes.Tanh: {
216            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
217            result = Interval.HyperbolicTangent(argumentInterval);
218            break;
219          }
220        //Exponential functions
221        case OpCodes.Log: {
222            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
223            result = Interval.Logarithm(argumentInterval);
224            break;
225          }
226        case OpCodes.Exp: {
227            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
228            result = Interval.Exponential(argumentInterval);
229            break;
230          }
231        case OpCodes.Square: {
232            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
233            result = Interval.Square(argumentInterval);
234            break;
235          }
236        case OpCodes.SquareRoot: {
237            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
238            result = Interval.SquareRoot(argumentInterval);
239            break;
240          }
241        case OpCodes.Cube: {
242            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
243            result = Interval.Cube(argumentInterval);
244            break;
245          }
246        case OpCodes.CubeRoot: {
247            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
248            result = Interval.CubicRoot(argumentInterval);
249            break;
250          }
251        case OpCodes.Absolute: {
252            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
253            result = Interval.Absolute(argumentInterval);
254            break;
255          }
256        case OpCodes.AnalyticQuotient: {
257            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
258            for (var i = 1; i < currentInstr.nArguments; i++) {
259              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
260              result = Interval.AnalyticalQuotient(result, argumentInterval);
261            }
262
263            break;
264          }
265        default:
266          throw new NotSupportedException($"The tree contains the unknown symbol {currentInstr.dynamicNode.Symbol}");
267      }
268
269      if (nodeIntervals != null)
270        nodeIntervals.Add(currentInstr.dynamicNode, result);
271
272      return result;
273    }
274
275    public static bool IsCompatible(ISymbolicExpressionTree tree) {
276      var containsUnknownSymbols = (
277        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
278        where
279          !(n.Symbol is Problems.DataAnalysis.Symbolic.Variable) &&
280          !(n.Symbol is Constant) &&
281          !(n.Symbol is StartSymbol) &&
282          !(n.Symbol is Addition) &&
283          !(n.Symbol is Subtraction) &&
284          !(n.Symbol is Multiplication) &&
285          !(n.Symbol is Division) &&
286          !(n.Symbol is Sine) &&
287          !(n.Symbol is Cosine) &&
288          !(n.Symbol is Tangent) &&
289          !(n.Symbol is Logarithm) &&
290          !(n.Symbol is Exponential) &&
291          !(n.Symbol is Square) &&
292          !(n.Symbol is SquareRoot) &&
293          !(n.Symbol is Cube) &&
294          !(n.Symbol is CubeRoot) &&
295          !(n.Symbol is Absolute) &&
296          !(n.Symbol is AnalyticQuotient)
297        select n).Any();
298      return !containsUnknownSymbols;
299    }
300  }
301}
Note: See TracBrowser for help on using the repository browser.