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 


33  namespace HeuristicLab.Algorithms.DataAnalysis.Symbolic {


34  [StorableClass]


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


36  public sealed class IntervalInterpreter : ParameterizedNamedItem, IStatefulItem {


37 


38  private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";


39  private static int InstructionCount = 0;


40 


41  public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {


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


43  }


44 


45  public int EvaluatedSolutions {


46  get { return EvaluatedSolutionsParameter.Value.Value; }


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


48  }


49 


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


51  private IntervalInterpreter(IntervalInterpreter original, Cloner cloner)


52  : base(original, cloner) { }


53 


54  public IntervalInterpreter()


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


56 


57  public override IDeepCloneable Clone(Cloner cloner) {


58  return new IntervalInterpreter(this, cloner);


59  }


60 


61  private readonly object syncRoot = new object();


62 


63  #region IStatefulItem Members


64  public void InitializeState() {


65  EvaluatedSolutions = 0;


66  }


67  public void ClearState() { }


68  #endregion


69 


70  private static void ResetInstrucitonCount() {


71  InstructionCount = 0;


72  }


73 


74 


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


76  lock (syncRoot) {


77  EvaluatedSolutions++;


78  ResetInstrucitonCount();


79  }


80  var instructions = PrepareInterpreterState(tree, rows, dataset);


81  var x = Evaluate(instructions);


82 


83  return x;


84  }


85 


86  public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, Dictionary<string, Interval> customIntervals, IEnumerable<int> rows = null) {


87  lock (syncRoot) {


88  EvaluatedSolutions++;


89  ResetInstrucitonCount();


90  }


91  var instructions = PrepareInterpreterState(tree, rows, null, customIntervals);


92  var x = Evaluate(instructions);


93 


94  return x;


95  }


96 


97  public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, IDataset dataset,


98  Dictionary<string, Interval> customIntervals, out Dictionary<ISymbolicExpressionTreeNode, Interval> intervals, IEnumerable<int> rows = null) {


99  lock (syncRoot) {


100  EvaluatedSolutions++;


101  ResetInstrucitonCount();


102  }


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


104  var instructions = PrepareInterpreterState(tree, rows, dataset, customIntervals);


105  var x = Evaluate(instructions, intervals);


106 


107  return x;


108  }


109 


110  public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, IDataset dataset,


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


112  lock(syncRoot) {


113  EvaluatedSolutions++;


114  ResetInstrucitonCount();


115  }


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


117  var instructions = PrepareInterpreterState(tree, rows, dataset);


118  var x = Evaluate(instructions, intervals);


119 


120  return x;


121  }


122 


123  public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, Dictionary<string, Interval> customIntervals,


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


125  lock (syncRoot) {


126  EvaluatedSolutions++;


127  ResetInstrucitonCount();


128  }


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


130  var instructions = PrepareInterpreterState(tree, rows, null, customIntervals);


131  var x = Evaluate(instructions, intervals);


132 


133  return x;


134  }


135 


136  private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree,


137  IEnumerable<int> rows = null, IDataset dataset = null, Dictionary<string, Interval> customIntervals = null) {


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


139 


140  if (dataset == null && customIntervals == null)


141  throw new Exception("No dataset or ranges for intervals are given!");


142 


143  if(rows == null)


144  rows = Enumerable.Range(0, dataset.Rows);


145 


146  foreach (Instruction instr in code) {


147  if (instr.opCode == OpCodes.Variable) {


148  var variableTreeNode = (VariableTreeNode)instr.dynamicNode;


149  IList<double> values = new List<double>();


150 


151  if (customIntervals != null) {


152  if (customIntervals.ContainsKey(variableTreeNode.VariableName)) {


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


154  }


155  } else {


156  foreach (var rowEnum in rows) {


157  values.Add(dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName)[rowEnum]);


158  }


159  instr.data = new Interval(values.Min(), values.Max());


160  }


161  }


162  }


163  return code;


164  }


165 


166  private Interval Evaluate(Instruction[] instructions, Dictionary<ISymbolicExpressionTreeNode, Interval> intervals = null) {


167  Instruction currentInstr = instructions[InstructionCount++];


168  Interval intermediate = null;


169 


170  switch (currentInstr.opCode) {


171  //Elementary arithmetic rules


172  case OpCodes.Add: {


173  intermediate = Evaluate(instructions, intervals);


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


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


176  }


177  break;


178  }


179  case OpCodes.Sub: {


180  intermediate = Evaluate(instructions, intervals);


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


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


183  }


184  break;


185  }


186  case OpCodes.Mul: {


187  intermediate = Evaluate(instructions, intervals);


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


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


190  }


191  break;


192  }


193  case OpCodes.Div: {


194  intermediate = Evaluate(instructions, intervals);


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


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


197  }


198  break;


199  }


200  //Trigonometric functions


201  case OpCodes.Sin: {


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


203  break;


204  }


205  case OpCodes.Cos: {


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


207  break;


208  }


209  case OpCodes.Tan: {


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


211  break;


212  }


213  //Exponential functions


214  case OpCodes.Log: {


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


216  break;


217  }


218  case OpCodes.Exp: {


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


220  break;


221  }


222  case OpCodes.Power: {


223  intermediate = Evaluate(instructions, intervals);


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


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


226  }


227  break;


228  }


229  case OpCodes.Square: {


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


231  break;


232  }


233  case OpCodes.Root: {


234  intermediate = Evaluate(instructions, intervals);


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


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


237  }


238  break;


239  }


240  case OpCodes.SquareRoot: {


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


242  break;


243  }


244  //Variables, Constants, ...


245  case OpCodes.Variable: {


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


247  return (Interval)currentInstr.data;


248  }


249  case OpCodes.Constant: {


250  var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;


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


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


253  return inter;


254  }


255  default:


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


257  }


258 


259  if (intervals != null)


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


261  return intermediate;


262  }


263 


264  public static bool IsCompatible(ISymbolicExpressionTree tree) {


265  var containsUnknownSyumbol = (


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


267  where


268  !(n.Symbol is StartSymbol) &&


269  !(n.Symbol is Addition) &&


270  !(n.Symbol is Subtraction) &&


271  !(n.Symbol is Multiplication) &&


272  !(n.Symbol is Division) &&


273  !(n.Symbol is Sine) &&


274  !(n.Symbol is Cosine) &&


275  !(n.Symbol is Tangent) &&


276  !(n.Symbol is Logarithm) &&


277  !(n.Symbol is Exponential) &&


278  !(n.Symbol is Power) &&


279  !(n.Symbol is Square) &&


280  !(n.Symbol is Root) &&


281  !(n.Symbol is SquareRoot) &&


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


283  !(n.Symbol is Constant)


284  select n).Any();


285  return !containsUnknownSyumbol;


286  }


287  }


288  }

