Free cookie consent management tool by TermsFeed Policy Generator

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

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

#3073

  • Split only variables occuring more than once in the model
  • Fixed returning interval from splitting method
File size: 26.2 KB
RevLine 
[16330]1#region License Information
[17631]2
[16330]3/* HeuristicLab
[17180]4 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[16330]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 */
[17631]21
[16330]22#endregion
23
24using System;
[16303]25using System.Collections.Generic;
[17637]26using System.Collections.ObjectModel;
[16303]27using System.Linq;
[17579]28using HEAL.Attic;
[16303]29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Data;
32using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[16367]33using HeuristicLab.Parameters;
[16303]34
[16377]35namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[16565]36  [StorableType("DE6C1E1E-D7C1-4070-847E-63B68562B10C")]
[17631]37  [Item("IntervalInterpreter", "Interpreter for calculation of intervals of symbolic models.")]
[16328]38  public sealed class IntervalInterpreter : ParameterizedNamedItem, IStatefulItem {
[16303]39    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
[17631]40    private const string MinSplittingWidthParameterName = "MinSplittingWidth";
41    private const string MaxSplittingDepthParameterName = "MaxSplittingDepth";
42    private const string UseIntervalSplittingParameterName = "UseIntervalSplitting";
[16330]43
[17631]44    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter =>
[17756]45      (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName];
[16303]46
[17631]47    public IFixedValueParameter<IntValue> MinSplittingWithParameter =>
[17756]48      (IFixedValueParameter<IntValue>)Parameters[MinSplittingWidthParameterName];
[17631]49
50    public IFixedValueParameter<IntValue> MaxSplittingDepthParameter =>
[17756]51      (IFixedValueParameter<IntValue>)Parameters[MaxSplittingDepthParameterName];
[17631]52
53    public IFixedValueParameter<BoolValue> UseIntervalSplittingParameter =>
[17756]54      (IFixedValueParameter<BoolValue>)Parameters[UseIntervalSplittingParameterName];
[17631]55
56    public int MinSplittingWidth {
57      get => MinSplittingWithParameter.Value.Value;
58      set => MinSplittingWithParameter.Value.Value = value;
59    }
60
61    public int MaxSplittingDepth {
62      get => MaxSplittingDepthParameter.Value.Value;
63      set => MaxSplittingDepthParameter.Value.Value = value;
64    }
65
66    public bool UseIntervalSplitting {
67      get => UseIntervalSplittingParameter.Value.Value;
68      set => UseIntervalSplittingParameter.Value.Value = value;
69    }
70
[16303]71    public int EvaluatedSolutions {
[17628]72      get => EvaluatedSolutionsParameter.Value.Value;
73      set => EvaluatedSolutionsParameter.Value.Value = value;
[16303]74    }
75
[16367]76    [StorableConstructor]
[16565]77    private IntervalInterpreter(StorableConstructorFlag _) : base(_) { }
[17631]78
[16328]79    private IntervalInterpreter(IntervalInterpreter original, Cloner cloner)
[17631]80      : base(original, cloner) { }
[17742]81
[16323]82    public IntervalInterpreter()
[17631]83      : base("IntervalInterpreter", "Interpreter for calculation of intervals of symbolic models.") {
84      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName,
85        "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
[17742]86      Parameters.Add(new FixedValueParameter<IntValue>(MinSplittingWidthParameterName,
87        "Minimum interval width until splitting is stopped", new IntValue(0)));
88      Parameters.Add(new FixedValueParameter<IntValue>(MaxSplittingDepthParameterName,
89        "Maximum recursion depth of the splitting", new IntValue(5)));
[17631]90      Parameters.Add(new FixedValueParameter<BoolValue>(UseIntervalSplittingParameterName, "", new BoolValue(false)));
[16367]91    }
[17742]92
[16303]93    public override IDeepCloneable Clone(Cloner cloner) {
[16323]94      return new IntervalInterpreter(this, cloner);
[16303]95    }
96
[16330]97    private readonly object syncRoot = new object();
98
[16328]99    #region IStatefulItem Members
[17631]100
[16328]101    public void InitializeState() {
102      EvaluatedSolutions = 0;
103    }
[17631]104
[16328]105    public void ClearState() { }
[17631]106
[16328]107    #endregion
108
[17631]109    public Interval GetSymbolicExpressionTreeInterval(
110      ISymbolicExpressionTree tree, IDataset dataset,
[17756]111      IEnumerable<int> rows = null) {
[16403]112      var variableRanges = DatasetUtil.GetVariableRanges(dataset, rows);
[17637]113      return GetSymbolicExpressionTreeInterval(tree, variableRanges);
[16330]114    }
115
[17631]116    public Interval GetSymbolicExpressionTreeIntervals(
117      ISymbolicExpressionTree tree, IDataset dataset,
118      out IDictionary<ISymbolicExpressionTreeNode, Interval>
[17756]119        nodeIntervals, IEnumerable<int> rows = null) {
[16403]120      var variableRanges = DatasetUtil.GetVariableRanges(dataset, rows);
[17637]121      return GetSymbolicExpressionTreeIntervals(tree, variableRanges, out nodeIntervals);
[16328]122    }
123
[17631]124    public Interval GetSymbolicExpressionTreeInterval(
125      ISymbolicExpressionTree tree,
[17756]126      IReadOnlyDictionary<string, Interval> variableRanges) {
[16364]127      lock (syncRoot) {
[16330]128        EvaluatedSolutions++;
129      }
[16328]130
[17631]131      Interval outputInterval;
132
[17637]133      if (UseIntervalSplitting) {
[17631]134        outputInterval = GetSymbolicExpressionTreeIntervals(tree, variableRanges,
[17756]135          out var _);
[17631]136      } else {
137        var instructionCount = 0;
138        var instructions = PrepareInterpreterState(tree, variableRanges);
139        outputInterval = Evaluate(instructions, ref instructionCount);
140      }
141
142      return outputInterval.LowerBound <= outputInterval.UpperBound
143        ? outputInterval
144        : new Interval(outputInterval.UpperBound, outputInterval.LowerBound);
[16328]145    }
146
[16364]147
[17631]148    public Interval GetSymbolicExpressionTreeIntervals(
149      ISymbolicExpressionTree tree,
[17637]150      IReadOnlyDictionary<string, Interval> variableRanges,
[17631]151      out IDictionary<ISymbolicExpressionTreeNode, Interval>
[17756]152        nodeIntervals) {
[16330]153      lock (syncRoot) {
154        EvaluatedSolutions++;
155      }
[17631]156
[16404]157      var intervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();
158      var instructions = PrepareInterpreterState(tree, variableRanges);
[16328]159
[17631]160      Interval outputInterval;
[17637]161      if (UseIntervalSplitting) {
[17760]162        //var variables = tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(x => x.VariableName).Distinct()
163        //                    .ToList();
164        var containsDependencyProblem = ContainsVariableMultipleTimes(tree, out var variables);
[17631]165
[17742]166        if (containsDependencyProblem) {
[17631]167          var currIndex = 0;
168          var currDepth = 0;
[17742]169          IDictionary<string, Interval> writeableVariableRanges =
170            variableRanges.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
171          //outputInterval = EvaluateRecursive(instructions, intervals, writeableVariableRanges, variables, MinSplittingWidth, MaxSplittingDepth,
172          //  ref currIndex, ref currDepth, tree);
[17760]173          outputInterval = EvaluateWithSplitting(instructions, intervals, writeableVariableRanges, variables);
[17631]174        } else {
175          var instructionCount = 0;
176          outputInterval = Evaluate(instructions, ref instructionCount, intervals);
177        }
178      } else {
179        var instructionCount = 0;
180        outputInterval = Evaluate(instructions, ref instructionCount, intervals);
181      }
182
[16629]183      nodeIntervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();
[16740]184      foreach (var kvp in intervals) {
[16629]185        var interval = kvp.Value;
186        if (interval.IsInfiniteOrUndefined || interval.LowerBound <= interval.UpperBound)
187          nodeIntervals.Add(kvp.Key, interval);
188        else
189          nodeIntervals.Add(kvp.Key, new Interval(interval.UpperBound, interval.LowerBound));
190      }
[16404]191
[16629]192      // because of numerical errors the bounds might be incorrect
193      if (outputInterval.IsInfiniteOrUndefined || outputInterval.LowerBound <= outputInterval.UpperBound)
194        return outputInterval;
[17631]195
196      return new Interval(outputInterval.UpperBound, outputInterval.LowerBound);
[16328]197    }
198
[16364]199
[17631]200    private static Instruction[] PrepareInterpreterState(
201      ISymbolicExpressionTree tree,
[17637]202      IReadOnlyDictionary<string, Interval> variableRanges) {
[16404]203      if (variableRanges == null)
204        throw new ArgumentNullException("No variablew ranges are present!", nameof(variableRanges));
[16328]205
[16404]206      //Check if all variables used in the tree are present in the dataset
[17742]207      foreach (var variable in tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName)
208                                   .Distinct())
[17631]209        if (!variableRanges.ContainsKey(variable))
210          throw new InvalidOperationException($"No ranges for variable {variable} is present");
[16330]211
[17631]212      var code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
213      foreach (var instr in code.Where(i => i.opCode == OpCodes.Variable)) {
[17756]214        var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
[16404]215        instr.data = variableRanges[variableTreeNode.VariableName];
[16303]216      }
[17631]217
[16330]218      return code;
[16303]219    }
220
[17742]221    public static Interval EvaluateWithSplitting(Instruction[] instructions,
222                                                 IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals,
[17760]223                                                 IDictionary<string, Interval> variableIntervals, List<string> multipleOccurenceVariables) {
[17756]224      var savedIntervals = variableIntervals.ToDictionary(entry => entry.Key, entry => entry.Value);
[17760]225      var min = FindBound(instructions, nodeIntervals, variableIntervals, multipleOccurenceVariables, minimization: true);
226      var max = FindBound(instructions, nodeIntervals, savedIntervals, multipleOccurenceVariables, minimization: false);
[17637]227
[17756]228      return new Interval(min, max);
[17742]229    }
230
[17756]231
232    private static double FindBound(Instruction[] instructions,
233                                    IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals,
[17760]234                                    IDictionary<string, Interval> variableIntervals, List<string> multipleOccurenceVariables, bool minimization = true) {
[17756]235      SortedSet<BoxBound> prioQ = new SortedSet<BoxBound>();
236
[17742]237      var ic = 0;
238      //Calculate full box
239      IReadOnlyDictionary<string, Interval> readonlyRanges = variableIntervals.ToDictionary(k => k.Key, k => k.Value);
[17756]240      var interval = Evaluate(instructions, ref ic, nodeIntervals, readonlyRanges);
241      // the order of keys in a dictionary is guaranteed to be the same order as values in a dictionary
242      // https://docs.microsoft.com/en-us/dotnet/api/system.collections.idictionary.keys?view=netcore-3.1#remarks
[17760]243      //var box = variableIntervals.Values;
244      //Box only contains intervals from multiple occurence variables
245      var box = multipleOccurenceVariables.Select(k => variableIntervals[k]);
[17757]246      if (minimization) {
[17756]247        prioQ.Add(new BoxBound(box, interval.LowerBound));
248      } else {
249        prioQ.Add(new BoxBound(box, -interval.UpperBound));
250      }
[17742]251
[17756]252      // TODO a fixed limit for depth?!
[17742]253      for (var depth = 0; depth < 200; ++depth) {
[17756]254        var currentBound = prioQ.Min;
255        prioQ.Remove(currentBound);
[17742]256
[17756]257        var newBoxes = Split(currentBound.box);
[17742]258
[17756]259        foreach (var newBox in newBoxes) {
[17760]260          //var intervalEnum = newBox.GetEnumerator();
261          //var keyEnum = readonlyRanges.Keys.GetEnumerator();
262          //while (intervalEnum.MoveNext() & keyEnum.MoveNext()) {
263          //  variableIntervals[keyEnum.Current] = intervalEnum.Current;
264          //}
265          //Set the splitted variables
[17756]266          var intervalEnum = newBox.GetEnumerator();
[17760]267          foreach (var key in multipleOccurenceVariables) {
268            intervalEnum.MoveNext();
269            variableIntervals[key] = intervalEnum.Current;
[17742]270          }
271
272          ic = 0;
273          var res = Evaluate(instructions, ref ic, nodeIntervals,
274            new ReadOnlyDictionary<string, Interval>(variableIntervals));
[17756]275          if (minimization) {
[17760]276            prioQ.Add(new BoxBound(newBox, res.LowerBound));
[17756]277          } else {
[17760]278            prioQ.Add(new BoxBound(newBox, -res.UpperBound));
[17756]279          }
[17742]280        }
281      }
282
[17757]283      return minimization ?
284        prioQ.First().bound :
[17756]285        -prioQ.First().bound;
[17742]286    }
287
288    private static IEnumerable<IEnumerable<Interval>> Split(List<Interval> box) {
[17756]289      var boxes = box.Select(region => region.Split()).Select(split => new List<Interval> { split.Item1, split.Item2 })
[17742]290                     .ToList();
291
292      return boxes.CartesianProduct();
293    }
294
[17756]295    // a multi-dimensional box with an associated bound
[17757]296    // boxbounds are ordered first by bound (smaller first), then by size of box (larger first) then by distance of bottom left corner to origin
[17756]297    private class BoxBound : IComparable<BoxBound> {
298      public List<Interval> box;
299      public double bound;
300      public BoxBound(IEnumerable<Interval> box, double bound) {
301        this.box = new List<Interval>(box);
302        this.bound = bound;
[17742]303      }
[17756]304      public int CompareTo(BoxBound other) {
305        if (bound != other.bound) return bound.CompareTo(other.bound);
[17757]306
[17756]307        var thisSize = box.Aggregate(1.0, (current, dimExtent) => current * dimExtent.Width);
308        var otherSize = other.box.Aggregate(1.0, (current, dimExtent) => current * dimExtent.Width);
[17757]309        if (thisSize != otherSize) return -thisSize.CompareTo(otherSize);
[17742]310
[17757]311        var thisDist = box.Sum(dimExtent => dimExtent.LowerBound * dimExtent.LowerBound);
312        var otherDist = other.box.Sum(dimExtent => dimExtent.LowerBound * dimExtent.LowerBound);
313        if (thisDist != otherDist) return thisDist.CompareTo(otherDist);
314
315        // which is smaller first along the dimensions?
316        for (int i = 0; i < box.Count; i++) {
317          if (box[i].LowerBound != other.box[i].LowerBound) return box[i].LowerBound.CompareTo(other.box[i].LowerBound);
[17742]318        }
[17757]319
[17756]320        return 0;
[17742]321      }
[17758]322    }
[17742]323
[17758]324    public static Interval EvaluateRecursive(
325      Instruction[] instructions,
326      IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals,
327      IDictionary<string, Interval> variableIntervals, IList<string> variables,
328      double minWidth, int maxDepth, ref int currIndex, ref int currDepth,
329      ISymbolicExpressionTree tree) {
330      Interval evaluate() {
331        var ic = 0;
332        IReadOnlyDictionary<string, Interval> readonlyRanges =
333          new ReadOnlyDictionary<string, Interval>(variableIntervals);
334        return Evaluate(instructions, ref ic, nodeIntervals, readonlyRanges);
335      }
[17631]336
[17758]337      Interval recurse(ref int idx, ref int depth) {
338        return EvaluateRecursive(instructions, nodeIntervals, variableIntervals, variables, minWidth, maxDepth, ref idx,
339          ref depth, tree);
340      }
[17631]341
342
[17758]343      var v = variables[currIndex];
344      var x = variableIntervals[v];
345      if (x.Width < minWidth || currDepth == maxDepth || !MultipleTimes(tree, v)) {
346        if (currIndex + 1 < variables.Count) {
347          currDepth = 0;
348          currIndex++;
349          var z = recurse(ref currIndex, ref currDepth);
350          currIndex--;
351          return z;
[17631]352        }
353
[17758]354        return evaluate();
[17631]355      }
356
[17758]357      var t = x.Split();
358      var xa = t.Item1;
359      var xb = t.Item2;
360      var d = currDepth;
361      currDepth = d + 1;
362      variableIntervals[v] = xa;
363      var ya = recurse(ref currIndex, ref currDepth);
364      currDepth = d + 1;
365      variableIntervals[v] = xb;
366      var yb = recurse(ref currIndex, ref currDepth);
367      variableIntervals[v] = x; // restore interval
368      return ya | yb;
369    }
[17631]370
[17758]371    public static Interval Evaluate(
372      Instruction[] instructions, ref int instructionCounter,
373      IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = null,
374      IReadOnlyDictionary<string, Interval> variableIntervals = null) {
375      var currentInstr = instructions[instructionCounter];
376      //Use ref parameter, because the tree will be iterated through recursively from the left-side branch to the right side
377      //Update instructionCounter, whenever Evaluate is called
378      instructionCounter++;
379      Interval result = null;
[16331]380
[17758]381      switch (currentInstr.opCode) {
382        //Variables, Constants, ...
383        case OpCodes.Variable: {
384            var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
385            var weightInterval = new Interval(variableTreeNode.Weight, variableTreeNode.Weight);
386            //var variableInterval = (Interval)currentInstr.data;
[16383]387
[17758]388            Interval variableInterval;
389            if (variableIntervals != null && variableIntervals.ContainsKey(variableTreeNode.VariableName))
390              variableInterval = variableIntervals[variableTreeNode.VariableName];
391            else
392              variableInterval = (Interval)currentInstr.data;
[17631]393
[17758]394            result = Interval.Multiply(variableInterval, weightInterval);
395            break;
396          }
397        case OpCodes.Constant: {
398            var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
399            result = new Interval(constTreeNode.Value, constTreeNode.Value);
400            break;
401          }
402        //Elementary arithmetic rules
403        case OpCodes.Add: {
404            //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
405            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
406            for (var i = 1; i < currentInstr.nArguments; i++) {
407              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
408              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
409              result = Interval.Add(result, argumentInterval);
[17756]410            }
411
[17758]412            break;
413          }
414        case OpCodes.Sub: {
415            //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
416            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
417            if (currentInstr.nArguments == 1)
418              result = Interval.Multiply(new Interval(-1, -1), result);
[16404]419
[17758]420            for (var i = 1; i < currentInstr.nArguments; i++) {
[17756]421              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
422              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
[17758]423              result = Interval.Subtract(result, argumentInterval);
[17756]424            }
[17758]425
426            break;
427          }
428        case OpCodes.Mul: {
429            //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
430            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
431            for (var i = 1; i < currentInstr.nArguments; i++) {
[17756]432              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
433              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
[17758]434              result = Interval.Multiply(result, argumentInterval);
[17756]435            }
[17758]436
437            break;
438          }
439        case OpCodes.Div: {
440            //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
441            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
442            if (currentInstr.nArguments == 1)
443              result = Interval.Divide(new Interval(1, 1), result);
444
445            for (var i = 1; i < currentInstr.nArguments; i++) {
[17756]446              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
447              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
[17758]448              result = Interval.Divide(result, argumentInterval);
[17756]449            }
[17758]450
451            break;
452          }
453        //Trigonometric functions
454        case OpCodes.Sin: {
455            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
456            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
457            result = Interval.Sine(argumentInterval);
458            break;
459          }
460        case OpCodes.Cos: {
461            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
462            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
463            result = Interval.Cosine(argumentInterval);
464            break;
465          }
466        case OpCodes.Tan: {
467            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
468            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
469            result = Interval.Tangens(argumentInterval);
470            break;
471          }
472        case OpCodes.Tanh: {
473            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
474            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
475            result = Interval.HyperbolicTangent(argumentInterval);
476            break;
477          }
478        //Exponential functions
479        case OpCodes.Log: {
480            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
481            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
482            result = Interval.Logarithm(argumentInterval);
483            break;
484          }
485        case OpCodes.Exp: {
486            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
487            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
488            result = Interval.Exponential(argumentInterval);
489            break;
490          }
491        case OpCodes.Square: {
492            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
493            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
494            result = Interval.Square(argumentInterval);
495            break;
496          }
497        case OpCodes.SquareRoot: {
498            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
499            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
500            result = Interval.SquareRoot(argumentInterval);
501            break;
502          }
503        case OpCodes.Cube: {
504            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
505            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
506            result = Interval.Cube(argumentInterval);
507            break;
508          }
509        case OpCodes.CubeRoot: {
510            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
511            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
512            result = Interval.CubicRoot(argumentInterval);
513            break;
514          }
515        case OpCodes.Absolute: {
516            //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
517            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
518            result = Interval.Absolute(argumentInterval);
519            break;
520          }
521        case OpCodes.AnalyticQuotient: {
522            //result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
523            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
524            for (var i = 1; i < currentInstr.nArguments; i++) {
[17756]525              //var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
526              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
[17758]527              result = Interval.AnalyticalQuotient(result, argumentInterval);
[17756]528            }
[17579]529
[17758]530            break;
531          }
532        default:
533          throw new NotSupportedException($"The tree contains the unknown symbol {currentInstr.dynamicNode.Symbol}");
534      }
[16331]535
[17758]536      if (!(nodeIntervals == null || nodeIntervals.ContainsKey(currentInstr.dynamicNode)))
537        nodeIntervals.Add(currentInstr.dynamicNode, result);
[16383]538
[17758]539      return result;
540    }
[16330]541
[17758]542    private static bool MultipleTimes(ISymbolicExpressionTree tree, string variable) {
543      var varlist = tree.IterateNodesPrefix().OfType<VariableTreeNode>().GroupBy(x => x.VariableName);
544      var group = varlist.Select(x => x.Key == variable).Count();
[17631]545
[17758]546      return group > 1;
547    }
[17631]548
[17760]549    private static bool ContainsVariableMultipleTimes(ISymbolicExpressionTree tree, out List<String> variables) {
550      variables = new List<string>();
[17758]551      var varlist = tree.IterateNodesPrefix().OfType<VariableTreeNode>().GroupBy(x => x.VariableName);
[17760]552      foreach (var group in varlist) {
553        if (group.Count() > 1) {
554          variables.Add(group.Key);
555        }
556      }
557
[17758]558      return varlist.Any(group => group.Count() > 1);
559    }
[17631]560
561
[17758]562    public static bool IsCompatible(ISymbolicExpressionTree tree) {
563      var containsUnknownSymbols = (
564        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
565        where
566          !(n.Symbol is Variable) &&
567          !(n.Symbol is Constant) &&
568          !(n.Symbol is StartSymbol) &&
569          !(n.Symbol is Addition) &&
570          !(n.Symbol is Subtraction) &&
571          !(n.Symbol is Multiplication) &&
572          !(n.Symbol is Division) &&
573          !(n.Symbol is Sine) &&
574          !(n.Symbol is Cosine) &&
575          !(n.Symbol is Tangent) &&
576          !(n.Symbol is HyperbolicTangent) &&
577          !(n.Symbol is Logarithm) &&
578          !(n.Symbol is Exponential) &&
579          !(n.Symbol is Square) &&
580          !(n.Symbol is SquareRoot) &&
581          !(n.Symbol is Cube) &&
582          !(n.Symbol is CubeRoot) &&
583          !(n.Symbol is Absolute) &&
584          !(n.Symbol is AnalyticQuotient)
585        select n).Any();
586      return !containsUnknownSymbols;
[16330]587    }
[17758]588  }
589}
Note: See TracBrowser for help on using the repository browser.