#region License Information /* HeuristicLab * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Problems.DataAnalysis; using HeuristicLab.Problems.DataAnalysis.Symbolic; using HeuristicLab.Parameters; namespace HeuristicLab.Algorithms.DataAnalysis.Symbolic { [StorableClass] [Item("IntervalInterpreter", "Intperter for calculation of intervals of symbolic models.")] public sealed class IntervalInterpreter : ParameterizedNamedItem, IStatefulItem { private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions"; public IFixedValueParameter EvaluatedSolutionsParameter { get { return (IFixedValueParameter)Parameters[EvaluatedSolutionsParameterName]; } } public int EvaluatedSolutions { get { return EvaluatedSolutionsParameter.Value.Value; } set { EvaluatedSolutionsParameter.Value.Value = value; } } [StorableConstructor] private IntervalInterpreter(bool deserializing) : base(deserializing) { } private IntervalInterpreter(IntervalInterpreter original, Cloner cloner) : base(original, cloner) { } public IntervalInterpreter() : base("IntervalInterpreter", "Intperter for calculation of intervals of symbolic models.") { Parameters.Add(new FixedValueParameter(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0))); } public override IDeepCloneable Clone(Cloner cloner) { return new IntervalInterpreter(this, cloner); } private readonly object syncRoot = new object(); #region IStatefulItem Members public void InitializeState() { EvaluatedSolutions = 0; } public void ClearState() { } #endregion public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable rows = null) { lock (syncRoot) { EvaluatedSolutions++; } int instructionCount = 0; var intervalBoundaries = DatasetUtil.GetVariableBoundaries(dataset, rows); var instructions = PrepareInterpreterState(tree, intervalBoundaries); var x = Evaluate(instructions, ref instructionCount); return x; } public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, IDataset dataset, out Dictionary intervals, IEnumerable rows = null) { lock (syncRoot) { EvaluatedSolutions++; } int instructionCount = 0; var intervalBoundaries = DatasetUtil.GetVariableBoundaries(dataset, rows); intervals = new Dictionary(); var instructions = PrepareInterpreterState(tree, intervalBoundaries); var x = Evaluate(instructions, ref instructionCount, intervals); return x; } public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, Dictionary customIntervals) { lock (syncRoot) { EvaluatedSolutions++; } int instructionCount = 0; var instructions = PrepareInterpreterState(tree, customIntervals); var x = Evaluate(instructions, ref instructionCount); return x; } public Interval GetSymbolicExressionTreeIntervals(ISymbolicExpressionTree tree, Dictionary customIntervals, out Dictionary intervals) { lock (syncRoot) { EvaluatedSolutions++; } int instructionCount = 0; intervals = new Dictionary(); var instructions = PrepareInterpreterState(tree, customIntervals); var x = Evaluate(instructions, ref instructionCount, intervals); return x; } private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree, Dictionary customIntervals) { Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode); if (customIntervals == null) throw new ArgumentException("No interval ranges are present!", nameof(customIntervals)); foreach (var variable in tree.IterateNodesPrefix().OfType().Select(n => n.VariableName).Distinct()) { if (!customIntervals.ContainsKey(variable)) throw new InvalidOperationException($"No ranges for variable {variable} is present"); } foreach (Instruction instr in code.Where(i => i.opCode == OpCodes.Variable)) { var variableTreeNode = (VariableTreeNode)instr.dynamicNode; instr.data = customIntervals[variableTreeNode.VariableName]; } return code; } private Interval Evaluate(Instruction[] instructions, ref int instructionCount, Dictionary intervals = null) { Instruction currentInstr = instructions[instructionCount++]; Interval result = null; switch (currentInstr.opCode) { //Elementary arithmetic rules case OpCodes.Add: { result = Evaluate(instructions, ref instructionCount, intervals); for (int i = 1; i < currentInstr.nArguments; i++) { result = Interval.Add(result, Evaluate(instructions, ref instructionCount, intervals)); } break; } case OpCodes.Sub: { result = Evaluate(instructions, ref instructionCount, intervals); for (int i = 1; i < currentInstr.nArguments; i++) { result = Interval.Subtract(result, Evaluate(instructions, ref instructionCount, intervals)); } break; } case OpCodes.Mul: { result = Evaluate(instructions, ref instructionCount, intervals); for (int i = 1; i < currentInstr.nArguments; i++) { result = Interval.Multiply(result, Evaluate(instructions, ref instructionCount, intervals)); } break; } case OpCodes.Div: { result = Evaluate(instructions, ref instructionCount, intervals); for (int i = 1; i < currentInstr.nArguments; i++) { result = Interval.Divide(result, Evaluate(instructions, ref instructionCount, intervals)); } break; } //Trigonometric functions case OpCodes.Sin: { result = Interval.Sine(Evaluate(instructions, ref instructionCount, intervals)); break; } case OpCodes.Cos: { result = Interval.Cosine(Evaluate(instructions, ref instructionCount, intervals)); break; } case OpCodes.Tan: { result = Interval.Tangens(Evaluate(instructions, ref instructionCount, intervals)); break; } //Exponential functions case OpCodes.Log: { result = Interval.Logarithm(Evaluate(instructions, ref instructionCount, intervals)); break; } case OpCodes.Exp: { result = Interval.Exponential(Evaluate(instructions, ref instructionCount, intervals)); break; } case OpCodes.Power: { result = Evaluate(instructions, ref instructionCount, intervals); for (int i = 1; i < currentInstr.nArguments; i++) { result = Interval.Power(result, Evaluate(instructions, ref instructionCount, intervals)); } break; } case OpCodes.Square: { result = Interval.Square(Evaluate(instructions, ref instructionCount, intervals)); break; } case OpCodes.Root: { result = Evaluate(instructions, ref instructionCount, intervals); for (int i = 1; i < currentInstr.nArguments; i++) { result = Interval.Root(result, Evaluate(instructions, ref instructionCount, intervals)); } break; } case OpCodes.SquareRoot: { result = Interval.SquareRoot(Evaluate(instructions, ref instructionCount, intervals)); break; } //Variables, Constants, ... case OpCodes.Variable: { intervals.Add(currentInstr.dynamicNode, (Interval)currentInstr.data); return (Interval)currentInstr.data; } case OpCodes.Constant: { var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode; var inter = new Interval(constTreeNode.Value, constTreeNode.Value); intervals.Add(currentInstr.dynamicNode, inter); return inter; } default: throw new NotSupportedException("Tree contains an unknown symbol."); } if (intervals != null) intervals.Add(currentInstr.dynamicNode, result); return result; } public static bool IsCompatible(ISymbolicExpressionTree tree) { var containsUnknownSyumbol = ( from n in tree.Root.GetSubtree(0).IterateNodesPrefix() where !(n.Symbol is StartSymbol) && !(n.Symbol is Addition) && !(n.Symbol is Subtraction) && !(n.Symbol is Multiplication) && !(n.Symbol is Division) && !(n.Symbol is Sine) && !(n.Symbol is Cosine) && !(n.Symbol is Tangent) && !(n.Symbol is Logarithm) && !(n.Symbol is Exponential) && !(n.Symbol is Power) && !(n.Symbol is Square) && !(n.Symbol is Root) && !(n.Symbol is SquareRoot) && !(n.Symbol is Problems.DataAnalysis.Symbolic.Variable) && !(n.Symbol is Constant) select n).Any(); return !containsUnknownSyumbol; } } }