1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022018 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 


22  using System;


23  using System.Collections.Generic;


24  using System.Linq;


25  using HeuristicLab.Common;


26  using HeuristicLab.Core;


27  using HeuristicLab.Data;


28  using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;


29  using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;


30  using HeuristicLab.Problems.DataAnalysis;


31  using HeuristicLab.Problems.DataAnalysis.Symbolic;


32  using HeuristicLab.Parameters;


33 


34  namespace HeuristicLab.Algorithms.DataAnalysis.Symbolic {


35  [StorableClass]


36  [Item("IntervalInterpreter", "Intperter for calculation of intervals of symbolic models.")]


37  public sealed class IntervalInterpreter : ParameterizedNamedItem, IStatefulItem {


38 


39  private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";


40  private static int InstructionCount = 0;


41 


42  public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {


43  get { return (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }


44  }


45 


46  public int EvaluatedSolutions {


47  get { return EvaluatedSolutionsParameter.Value.Value; }


48  set { EvaluatedSolutionsParameter.Value.Value = value; }


49  }


50 


51  [StorableConstructor]


52  private IntervalInterpreter(bool deserializing) : base(deserializing) { }


53  private IntervalInterpreter(IntervalInterpreter original, Cloner cloner)


54  : base(original, cloner) { }


55 


56  public IntervalInterpreter()


57  : base("IntervalInterpreter", "Intperter for calculation of intervals of symbolic models.") {


58  Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));


59  }


60 


61  public override IDeepCloneable Clone(Cloner cloner) {


62  return new IntervalInterpreter(this, cloner);


63  }


64 


65  private readonly object syncRoot = new object();


66 


67  #region IStatefulItem Members


68  public void InitializeState() {


69  EvaluatedSolutions = 0;


70  }


71  public void ClearState() { }


72  #endregion


73 


74  private static void ResetInstrucitonCount() {


75  InstructionCount = 0;


76  }


77 


78 


79  public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable<int> rows = null) {


80  lock (syncRoot) {


81  EvaluatedSolutions++;


82  ResetInstrucitonCount();


83  }


84  var intervalBoundaries = DatasetUtil.GetVariableBoundaries(dataset, rows);


85  var instructions = PrepareInterpreterState(tree, intervalBoundaries);


86  var x = Evaluate(instructions);


87 


88  return x;


89  }


90 


91  public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, IDataset dataset,


92  out Dictionary<ISymbolicExpressionTreeNode, Interval> intervals, IEnumerable<int> rows = null) {


93  lock (syncRoot) {


94  EvaluatedSolutions++;


95  ResetInstrucitonCount();


96  }


97  var intervalBoundaries = DatasetUtil.GetVariableBoundaries(dataset, rows);


98  intervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();


99  var instructions = PrepareInterpreterState(tree, intervalBoundaries);


100  var x = Evaluate(instructions, intervals);


101 


102  return x;


103  }


104 


105  public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, Dictionary<string, Interval> customIntervals) {


106  lock (syncRoot) {


107  EvaluatedSolutions++;


108  ResetInstrucitonCount();


109  }


110  var instructions = PrepareInterpreterState(tree, customIntervals);


111  var x = Evaluate(instructions);


112 


113  return x;


114  }


115 


116 


117  public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree,


118  Dictionary<string, Interval> customIntervals, out Dictionary<ISymbolicExpressionTreeNode, Interval> intervals) {


119  lock (syncRoot) {


120  EvaluatedSolutions++;


121  ResetInstrucitonCount();


122  }


123  intervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();


124  var instructions = PrepareInterpreterState(tree, customIntervals);


125  var x = Evaluate(instructions, intervals);


126 


127  return x;


128  }


129 


130 


131  private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree, Dictionary<string, Interval> customIntervals) {


132  Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);


133 


134  if (customIntervals == null)


135  throw new ArgumentException("No interval ranges are present!", nameof(customIntervals));


136 


137  foreach (var variable in tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName).Distinct()) {


138  if (!customIntervals.ContainsKey(variable)) throw new InvalidOperationException($"No ranges for variable {variable} is present");


139  }


140 


141  foreach (Instruction instr in code.Where(i => i.opCode == OpCodes.Variable)) {


142  var variableTreeNode = (VariableTreeNode)instr.dynamicNode;


143  instr.data = customIntervals[variableTreeNode.VariableName];


144  }


145  return code;


146  }


147 


148  private Interval Evaluate(Instruction[] instructions, Dictionary<ISymbolicExpressionTreeNode,


149  Interval> intervals = null) {


150  Instruction currentInstr = instructions[InstructionCount++];


151  Interval intermediate = null;


152 


153  switch (currentInstr.opCode) {


154  //Elementary arithmetic rules


155  case OpCodes.Add: {


156  intermediate = Evaluate(instructions, intervals);


157  for (int i = 1; i < currentInstr.nArguments; i++) {


158  intermediate = Interval.Add(intermediate, Evaluate(instructions, intervals));


159  }


160  break;


161  }


162  case OpCodes.Sub: {


163  intermediate = Evaluate(instructions, intervals);


164  for (int i = 1; i < currentInstr.nArguments; i++) {


165  intermediate = Interval.Subtract(intermediate, Evaluate(instructions, intervals));


166  }


167  break;


168  }


169  case OpCodes.Mul: {


170  intermediate = Evaluate(instructions, intervals);


171  for (int i = 1; i < currentInstr.nArguments; i++) {


172  intermediate = Interval.Multiply(intermediate, Evaluate(instructions, intervals));


173  }


174  break;


175  }


176  case OpCodes.Div: {


177  intermediate = Evaluate(instructions, intervals);


178  for (int i = 1; i < currentInstr.nArguments; i++) {


179  intermediate = Interval.Divide(intermediate, Evaluate(instructions, intervals));


180  }


181  break;


182  }


183  //Trigonometric functions


184  case OpCodes.Sin: {


185  intermediate = Interval.Sine(Evaluate(instructions, intervals));


186  break;


187  }


188  case OpCodes.Cos: {


189  intermediate = Interval.Cosine(Evaluate(instructions, intervals));


190  break;


191  }


192  case OpCodes.Tan: {


193  intermediate = Interval.Tangens(Evaluate(instructions, intervals));


194  break;


195  }


196  //Exponential functions


197  case OpCodes.Log: {


198  intermediate = Interval.Logarithm(Evaluate(instructions, intervals));


199  break;


200  }


201  case OpCodes.Exp: {


202  intermediate = Interval.Exponential(Evaluate(instructions, intervals));


203  break;


204  }


205  case OpCodes.Power: {


206  intermediate = Evaluate(instructions, intervals);


207  for (int i = 1; i < currentInstr.nArguments; i++) {


208  intermediate = Interval.Power(intermediate, Evaluate(instructions, intervals));


209  }


210  break;


211  }


212  case OpCodes.Square: {


213  intermediate = Interval.Square(Evaluate(instructions, intervals));


214  break;


215  }


216  case OpCodes.Root: {


217  intermediate = Evaluate(instructions, intervals);


218  for (int i = 1; i < currentInstr.nArguments; i++) {


219  intermediate = Interval.Root(intermediate, Evaluate(instructions, intervals));


220  }


221  break;


222  }


223  case OpCodes.SquareRoot: {


224  intermediate = Interval.SquareRoot(Evaluate(instructions, intervals));


225  break;


226  }


227  //Variables, Constants, ...


228  case OpCodes.Variable: {


229  intervals.Add(currentInstr.dynamicNode, (Interval)currentInstr.data);


230  return (Interval)currentInstr.data;


231  }


232  case OpCodes.Constant: {


233  var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;


234  var inter = new Interval(constTreeNode.Value, constTreeNode.Value);


235  intervals.Add(currentInstr.dynamicNode, inter);


236  return inter;


237  }


238  default:


239  throw new NotSupportedException("Tree contains an unknown symbol.");


240  }


241 


242  if (intervals != null)


243  intervals.Add(currentInstr.dynamicNode, intermediate);


244  return intermediate;


245  }


246 


247  public static bool IsCompatible(ISymbolicExpressionTree tree) {


248  var containsUnknownSyumbol = (


249  from n in tree.Root.GetSubtree(0).IterateNodesPrefix()


250  where


251  !(n.Symbol is StartSymbol) &&


252  !(n.Symbol is Addition) &&


253  !(n.Symbol is Subtraction) &&


254  !(n.Symbol is Multiplication) &&


255  !(n.Symbol is Division) &&


256  !(n.Symbol is Sine) &&


257  !(n.Symbol is Cosine) &&


258  !(n.Symbol is Tangent) &&


259  !(n.Symbol is Logarithm) &&


260  !(n.Symbol is Exponential) &&


261  !(n.Symbol is Power) &&


262  !(n.Symbol is Square) &&


263  !(n.Symbol is Root) &&


264  !(n.Symbol is SquareRoot) &&


265  !(n.Symbol is Problems.DataAnalysis.Symbolic.Variable) &&


266  !(n.Symbol is Constant)


267  select n).Any();


268  return !containsUnknownSyumbol;


269  }


270  }


271  }

