Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeVectorInterpreter.cs @ 17930

Last change on this file since 17930 was 17930, checked in by pfleck, 3 years ago

#3040 Reworked external dependencies and merged some libraries (ILmerge) to avoid versions conflicts occuring on Hive.

File size: 50.3 KB
RevLine 
[5571]1#region License Information
2/* HeuristicLab
[17180]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[5571]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;
[17573]24using System.Linq;
[5571]25using HeuristicLab.Common;
26using HeuristicLab.Core;
[6740]27using HeuristicLab.Data;
[5571]28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[6740]29using HeuristicLab.Parameters;
[16565]30using HEAL.Attic;
[17721]31using MathNet.Numerics;
[17448]32using MathNet.Numerics.Statistics;
[17455]33using DoubleVector = MathNet.Numerics.LinearAlgebra.Vector<double>;
34
[5571]35namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[17455]36  [StorableType("DE68A1D9-5AFC-4DDD-AB62-29F3B8FC28E0")]
37  [Item("SymbolicDataAnalysisExpressionTreeVectorInterpreter", "Interpreter for symbolic expression trees including vector arithmetic.")]
38  public class SymbolicDataAnalysisExpressionTreeVectorInterpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter {
[17467]39    [StorableType("2612504E-AD5F-4AE2-B60E-98A5AB59E164")]
40    public enum Aggregation {
41      Mean,
42      Median,
43      Sum,
[17573]44      First,
[17721]45      L1Norm,
46      L2Norm,
[17467]47      NaN,
48      Exception
49    }
[17721]50    public static double Aggregate(Aggregation aggregation, DoubleVector vector) {
51      switch (aggregation) {
52        case Aggregation.Mean: return Statistics.Mean(vector);
53        case Aggregation.Median: return Statistics.Median(vector);
54        case Aggregation.Sum: return vector.Sum();
55        case Aggregation.First: return vector.First();
56        case Aggregation.L1Norm: return vector.L1Norm();
57        case Aggregation.L2Norm: return vector.L2Norm();
58        case Aggregation.NaN: return double.NaN;
59        case Aggregation.Exception: throw new InvalidOperationException("Result of the tree is not a scalar.");
60        default: throw new ArgumentOutOfRangeException(nameof(aggregation), aggregation, null);
61      }
62    }
[17455]63
[17721]64    [StorableType("73DCBB45-916F-4139-8ADC-57BA610A1B66")]
65    public enum VectorLengthStrategy {
66      ExceptionIfDifferent,
67      FillShorterWithNaN,
68      FillShorterWithNeutralElement,
69      CutLonger,
70      ResampleToLonger,
71      ResampleToShorter,
72      CycleShorter
73    }
74
75    #region Implementation VectorLengthStrategy
76    public static (DoubleVector, DoubleVector) ExceptionIfDifferent(DoubleVector lhs, DoubleVector rhs) {
77      if (lhs.Count != rhs.Count)
78        throw new InvalidOperationException($"Vector Lengths incompatible ({lhs.Count} vs. {rhs.Count}");
79      return (lhs, rhs);
80    }
81
82    public static (DoubleVector, DoubleVector) FillShorter(DoubleVector lhs, DoubleVector rhs, double fillElement) {
83      var targetLength = Math.Max(lhs.Count, rhs.Count);
84
85      DoubleVector PadVector(DoubleVector v) {
86        if (v.Count == targetLength) return v;
87        var p = DoubleVector.Build.Dense(targetLength, fillElement);
88        v.CopySubVectorTo(p, 0, 0, v.Count);
89        return p;
90      }
91
92      return (PadVector(lhs), PadVector(rhs));
93    }
94
95    public static (DoubleVector, DoubleVector) CutLonger(DoubleVector lhs, DoubleVector rhs) {
96      var targetLength = Math.Min(lhs.Count, rhs.Count);
97
98      DoubleVector CutVector(DoubleVector v) {
99        if (v.Count == targetLength) return v;
100        return v.SubVector(0, targetLength);
101      }
102
103      return (CutVector(lhs), CutVector(rhs));
104    }
105
106    private static DoubleVector ResampleToLength(DoubleVector v, int targetLength) {
107      if (v.Count == targetLength) return v;
108
109      var indices = Enumerable.Range(0, v.Count).Select(x => (double)x);
110      var interpolation = Interpolate.Linear(indices, v);
111
112      var resampledIndices = Enumerable.Range(0, targetLength).Select(i => (double)i / targetLength * v.Count);
113      var interpolatedValues = resampledIndices.Select(interpolation.Interpolate);
114
115      return DoubleVector.Build.DenseOfEnumerable(interpolatedValues);
116    }
117    public static (DoubleVector, DoubleVector) ResampleToLonger(DoubleVector lhs, DoubleVector rhs) {
118      var maxLength = Math.Max(lhs.Count, rhs.Count);
119      return (ResampleToLength(lhs, maxLength), ResampleToLength(rhs, maxLength));
120    }
121    public static (DoubleVector, DoubleVector) ResampleToShorter(DoubleVector lhs, DoubleVector rhs) {
122      var minLength = Math.Min(lhs.Count, rhs.Count);
123      return (ResampleToLength(lhs, minLength), ResampleToLength(rhs, minLength));
124    }
125
126    public static (DoubleVector, DoubleVector) CycleShorter(DoubleVector lhs, DoubleVector rhs) {
127      var targetLength = Math.Max(lhs.Count, rhs.Count);
128
129      DoubleVector CycleVector(DoubleVector v) {
130        if (v.Count == targetLength) return v;
131        var cycledValues = Enumerable.Range(0, targetLength).Select(i => v[i % v.Count]);
132        return DoubleVector.Build.DenseOfEnumerable(cycledValues);
133      }
134
135      return (CycleVector(lhs), CycleVector(rhs));
136    }
137    #endregion
138
139    public static (DoubleVector lhs, DoubleVector rhs) ApplyVectorLengthStrategy(VectorLengthStrategy strategy, DoubleVector lhs, DoubleVector rhs,
140      double neutralElement = double.NaN) {
141
142      switch (strategy) {
143        case VectorLengthStrategy.ExceptionIfDifferent: return ExceptionIfDifferent(lhs, rhs);
144        case VectorLengthStrategy.FillShorterWithNaN: return FillShorter(lhs, rhs, double.NaN);
145        case VectorLengthStrategy.FillShorterWithNeutralElement: return FillShorter(lhs, rhs, neutralElement);
146        case VectorLengthStrategy.CutLonger: return CutLonger(lhs, rhs);
147        case VectorLengthStrategy.ResampleToLonger: return ResampleToLonger(lhs, rhs);
148        case VectorLengthStrategy.ResampleToShorter: return ResampleToShorter(lhs, rhs);
149        case VectorLengthStrategy.CycleShorter: return CycleShorter(lhs, rhs);
150        default: throw new ArgumentOutOfRangeException(nameof(strategy), strategy, null);
151      }
152    }
153
[17604]154    #region Aggregation Symbols
155    private static Type[] AggregationSymbols = new[] {
156      typeof(Sum), typeof(Mean), typeof(Length), typeof(StandardDeviation), typeof(Variance),
157      typeof(EuclideanDistance), typeof(Covariance)
158    };
159    #endregion
160
[7615]161    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
[17467]162    private const string FinalAggregationParameterName = "FinalAggregation";
[17721]163    private const string DifferentVectorLengthStrategyParameterName = "DifferentVectorLengthStrategy";
[5571]164
[13248]165    public override bool CanChangeName {
166      get { return false; }
167    }
[5571]168
[13248]169    public override bool CanChangeDescription {
170      get { return false; }
171    }
172
[5749]173    #region parameter properties
[13248]174    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {
175      get { return (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
[7615]176    }
[17467]177    public IFixedValueParameter<EnumValue<Aggregation>> FinalAggregationParameter {
178      get { return (IFixedValueParameter<EnumValue<Aggregation>>)Parameters[FinalAggregationParameterName]; }
179    }
[17721]180    public IFixedValueParameter<EnumValue<VectorLengthStrategy>> DifferentVectorLengthStrategyParameter {
181      get { return (IFixedValueParameter<EnumValue<VectorLengthStrategy>>)Parameters[DifferentVectorLengthStrategyParameterName]; }
182    }
[5749]183    #endregion
184
185    #region properties
[13248]186    public int EvaluatedSolutions {
187      get { return EvaluatedSolutionsParameter.Value.Value; }
188      set { EvaluatedSolutionsParameter.Value.Value = value; }
[7615]189    }
[17467]190    public Aggregation FinalAggregation {
191      get { return FinalAggregationParameter.Value.Value; }
192      set { FinalAggregationParameter.Value.Value = value; }
193    }
[17721]194    public VectorLengthStrategy DifferentVectorLengthStrategy {
195      get { return DifferentVectorLengthStrategyParameter.Value.Value; }
196      set { DifferentVectorLengthStrategyParameter.Value.Value = value; }
197    }
[5749]198    #endregion
199
[5571]200    [StorableConstructor]
[17455]201    protected SymbolicDataAnalysisExpressionTreeVectorInterpreter(StorableConstructorFlag _) : base(_) { }
[13248]202
[17455]203    protected SymbolicDataAnalysisExpressionTreeVectorInterpreter(SymbolicDataAnalysisExpressionTreeVectorInterpreter original, Cloner cloner)
[13251]204      : base(original, cloner) { }
[13248]205
[5571]206    public override IDeepCloneable Clone(Cloner cloner) {
[17455]207      return new SymbolicDataAnalysisExpressionTreeVectorInterpreter(this, cloner);
[5571]208    }
209
[17455]210    public SymbolicDataAnalysisExpressionTreeVectorInterpreter()
[17830]211      : this("SymbolicDataAnalysisExpressionTreeVectorInterpreter", "Interpreter for symbolic expression trees including vector arithmetic.") { }
[5571]212
[17455]213    protected SymbolicDataAnalysisExpressionTreeVectorInterpreter(string name, string description)
[8436]214      : base(name, description) {
[13248]215      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
[17467]216      Parameters.Add(new FixedValueParameter<EnumValue<Aggregation>>(FinalAggregationParameterName, "If root node of the expression tree results in a Vector it is aggregated according to this parameter", new EnumValue<Aggregation>(Aggregation.Mean)));
[17721]217      Parameters.Add(new FixedValueParameter<EnumValue<VectorLengthStrategy>>(DifferentVectorLengthStrategyParameterName, "", new EnumValue<VectorLengthStrategy>(VectorLengthStrategy.ExceptionIfDifferent)));
[8436]218    }
219
[7615]220    [StorableHook(HookType.AfterDeserialization)]
221    private void AfterDeserialization() {
[17467]222      if (!Parameters.ContainsKey(FinalAggregationParameterName)) {
223        Parameters.Add(new FixedValueParameter<EnumValue<Aggregation>>(FinalAggregationParameterName, "If root node of the expression tree results in a Vector it is aggregated according to this parameter", new EnumValue<Aggregation>(Aggregation.Mean)));
224      }
[17721]225      if (!Parameters.ContainsKey(DifferentVectorLengthStrategyParameterName)) {
226        Parameters.Add(new FixedValueParameter<EnumValue<VectorLengthStrategy>>(DifferentVectorLengthStrategyParameterName, "", new EnumValue<VectorLengthStrategy>(VectorLengthStrategy.ExceptionIfDifferent)));
227      }
[7615]228    }
229
230    #region IStatefulItem
231    public void InitializeState() {
[13248]232      EvaluatedSolutions = 0;
[7615]233    }
234
[13248]235    public void ClearState() { }
[7615]236    #endregion
237
[13251]238    private readonly object syncRoot = new object();
[17455]239    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable<int> rows) {
[13251]240      lock (syncRoot) {
[13248]241        EvaluatedSolutions++; // increment the evaluated solutions counter
[9004]242      }
[8436]243      var state = PrepareInterpreterState(tree, dataset);
244
245      foreach (var rowEnum in rows) {
246        int row = rowEnum;
[17455]247        var result = Evaluate(dataset, ref row, state);
[17463]248        if (result.IsScalar)
249          yield return result.Scalar;
[17467]250        else if (result.IsVector) {
[17721]251          yield return Aggregate(FinalAggregation, result.Vector);
[17467]252        } else
[17463]253          yield return double.NaN;
[8436]254        state.Reset();
255      }
[7154]256    }
257
[17726]258    public IEnumerable<Dictionary<ISymbolicExpressionTreeNode, EvaluationResult>> GetIntermediateNodeValues(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable<int> rows) {
259      var state = PrepareInterpreterState(tree, dataset);
260
261      foreach (var rowEnum in rows) {
262        int row = rowEnum;
263        var traceDict = new Dictionary<ISymbolicExpressionTreeNode, EvaluationResult>();
264        var result = Evaluate(dataset, ref row, state, traceDict);
265        traceDict.Add(tree.Root.GetSubtree(0), result); // Add StartSymbol
266        yield return traceDict;
267        state.Reset();
268      }
269    }
270
[12509]271    private static InterpreterState PrepareInterpreterState(ISymbolicExpressionTree tree, IDataset dataset) {
[8436]272      Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
[5987]273      int necessaryArgStackSize = 0;
[8436]274      foreach (Instruction instr in code) {
[6860]275        if (instr.opCode == OpCodes.Variable) {
[8436]276          var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
[17460]277          if (dataset.VariableHasType<double>(variableTreeNode.VariableName))
278            instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
279          else if (dataset.VariableHasType<DoubleVector>(variableTreeNode.VariableName))
280            instr.data = dataset.GetReadOnlyDoubleVectorValues(variableTreeNode.VariableName);
281          else throw new NotSupportedException($"Type of variable {variableTreeNode.VariableName} is not supported.");
[14826]282        } else if (instr.opCode == OpCodes.FactorVariable) {
283          var factorTreeNode = instr.dynamicNode as FactorVariableTreeNode;
284          instr.data = dataset.GetReadOnlyStringValues(factorTreeNode.VariableName);
285        } else if (instr.opCode == OpCodes.BinaryFactorVariable) {
286          var factorTreeNode = instr.dynamicNode as BinaryFactorVariableTreeNode;
287          instr.data = dataset.GetReadOnlyStringValues(factorTreeNode.VariableName);
[5571]288        } else if (instr.opCode == OpCodes.LagVariable) {
[8436]289          var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
[9828]290          instr.data = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
[6860]291        } else if (instr.opCode == OpCodes.VariableCondition) {
[8436]292          var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
[9828]293          instr.data = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
[5987]294        } else if (instr.opCode == OpCodes.Call) {
295          necessaryArgStackSize += instr.nArguments + 1;
[5571]296        }
297      }
[8436]298      return new InterpreterState(code, necessaryArgStackSize);
299    }
[5571]300
[17455]301
302    public struct EvaluationResult {
303      public double Scalar { get; }
304      public bool IsScalar => !double.IsNaN(Scalar);
305
306      public DoubleVector Vector { get; }
[17465]307      public bool IsVector => !(Vector.Count == 1 && double.IsNaN(Vector[0]));
[17455]308
309      public bool IsNaN => !IsScalar && !IsVector;
310
311      public EvaluationResult(double scalar) {
312        Scalar = scalar;
[17465]313        Vector = NaNVector;
[17455]314      }
315      public EvaluationResult(DoubleVector vector) {
[17463]316        if (vector == null) throw new ArgumentNullException(nameof(vector));
[17455]317        Vector = vector;
318        Scalar = double.NaN;
319      }
320
321      public override string ToString() {
322        if (IsScalar) return Scalar.ToString();
323        if (IsVector) return Vector.ToVectorString();
324        return "NaN";
325      }
326
[17465]327      private static readonly DoubleVector NaNVector = DoubleVector.Build.Dense(1, double.NaN);
[17455]328      public static readonly EvaluationResult NaN = new EvaluationResult(double.NaN);
329    }
330
331    private static EvaluationResult ArithmeticApply(EvaluationResult lhs, EvaluationResult rhs,
[17721]332      Func<DoubleVector, DoubleVector, (DoubleVector, DoubleVector)> lengthStrategy,
[17455]333      Func<double, double, double> ssFunc = null,
334      Func<double, DoubleVector, DoubleVector> svFunc = null,
335      Func<DoubleVector, double, DoubleVector> vsFunc = null,
336      Func<DoubleVector, DoubleVector, DoubleVector> vvFunc = null) {
[17721]337
[17455]338      if (lhs.IsScalar && rhs.IsScalar && ssFunc != null) return new EvaluationResult(ssFunc(lhs.Scalar, rhs.Scalar));
339      if (lhs.IsScalar && rhs.IsVector && svFunc != null) return new EvaluationResult(svFunc(lhs.Scalar, rhs.Vector));
340      if (lhs.IsVector && rhs.IsScalar && vsFunc != null) return new EvaluationResult(vsFunc(lhs.Vector, rhs.Scalar));
[17721]341      if (lhs.IsVector && rhs.IsVector && vvFunc != null) {
342        if (lhs.Vector.Count == rhs.Vector.Count) {
343          return new EvaluationResult(vvFunc(lhs.Vector, rhs.Vector));
344        } else {
345          var (lhsVector, rhsVector) = lengthStrategy(lhs.Vector, rhs.Vector);
346          return new EvaluationResult(vvFunc(lhsVector, rhsVector));
347        }
348      }
[17463]349      return EvaluationResult.NaN;
[17455]350    }
351
352    private static EvaluationResult FunctionApply(EvaluationResult val,
353      Func<double, double> sFunc = null,
354      Func<DoubleVector, DoubleVector> vFunc = null) {
355      if (val.IsScalar && sFunc != null) return new EvaluationResult(sFunc(val.Scalar));
356      if (val.IsVector && vFunc != null) return new EvaluationResult(vFunc(val.Vector));
[17463]357      return EvaluationResult.NaN;
[17455]358    }
[17460]359    private static EvaluationResult AggregateApply(EvaluationResult val,
360      Func<double, double> sFunc = null,
361      Func<DoubleVector, double> vFunc = null) {
362      if (val.IsScalar && sFunc != null) return new EvaluationResult(sFunc(val.Scalar));
363      if (val.IsVector && vFunc != null) return new EvaluationResult(vFunc(val.Vector));
[17463]364      return EvaluationResult.NaN;
[17460]365    }
[17573]366
[17726]367    private static EvaluationResult WindowedAggregateApply(EvaluationResult val, WindowedSymbolTreeNode node,
[17573]368      Func<double, double> sFunc = null,
369      Func<DoubleVector, double> vFunc = null) {
370
371      var offset = node.Offset;
372      var length = node.Length;
373
374      DoubleVector SubVector(DoubleVector v) {
375        int index = (int)(offset * v.Count);
376        int count = (int)(length * (v.Count - index));
377        return v.SubVector(index, count);
378      };
379
380      if (val.IsScalar && sFunc != null) return new EvaluationResult(sFunc(val.Scalar));
381      if (val.IsVector && vFunc != null) return new EvaluationResult(vFunc(SubVector(val.Vector)));
382      return EvaluationResult.NaN;
383    }
[17726]384    private static EvaluationResult WindowedFunctionApply(EvaluationResult val, IWindowedSymbolTreeNode node,
385      Func<double, double> sFunc = null,
386      Func<DoubleVector, DoubleVector> vFunc = null) {
387      var offset = node.Offset;
388      var length = node.Length;
389
390      DoubleVector SubVector(DoubleVector v) {
391        int index = (int)(offset * v.Count);
392        int count = (int)(length * (v.Count - index));
393        return v.SubVector(index, count);
394      };
395
396      if (val.IsScalar && sFunc != null) return new EvaluationResult(sFunc(val.Scalar));
397      if (val.IsVector && vFunc != null) return new EvaluationResult(vFunc(SubVector(val.Vector)));
398      return EvaluationResult.NaN;
399    }
400
[17554]401    private static EvaluationResult AggregateMultipleApply(EvaluationResult lhs, EvaluationResult rhs,
[17721]402      Func<DoubleVector, DoubleVector, (DoubleVector, DoubleVector)> lengthStrategy,
[17554]403      Func<double, double, double> ssFunc = null,
404      Func<double, DoubleVector, double> svFunc = null,
405      Func<DoubleVector, double, double> vsFunc = null,
406      Func<DoubleVector, DoubleVector, double> vvFunc = null) {
407      if (lhs.IsScalar && rhs.IsScalar && ssFunc != null) return new EvaluationResult(ssFunc(lhs.Scalar, rhs.Scalar));
408      if (lhs.IsScalar && rhs.IsVector && svFunc != null) return new EvaluationResult(svFunc(lhs.Scalar, rhs.Vector));
409      if (lhs.IsVector && rhs.IsScalar && vsFunc != null) return new EvaluationResult(vsFunc(lhs.Vector, rhs.Scalar));
[17721]410      if (lhs.IsVector && rhs.IsVector && vvFunc != null) {
411        if (lhs.Vector.Count == rhs.Vector.Count) {
412          return new EvaluationResult(vvFunc(lhs.Vector, rhs.Vector));
413        } else {
414          var (lhsVector, rhsVector) = lengthStrategy(lhs.Vector, rhs.Vector);
415          return new EvaluationResult(vvFunc(lhsVector, rhsVector));
416        }
417      }
[17554]418      return EvaluationResult.NaN;
419    }
[17455]420
[17604]421    public virtual Type GetNodeType(ISymbolicExpressionTreeNode node) {
422      if (node.DataType != null)
423        return node.DataType;
[17593]424
[17604]425      if (AggregationSymbols.Contains(node.Symbol.GetType()))
426        return typeof(double);
[17593]427
[17604]428      var argumentTypes = node.Subtrees.Select(GetNodeType);
429      if (argumentTypes.Any(t => t == typeof(DoubleVector)))
430        return typeof(DoubleVector);
[17593]431
[17604]432      return typeof(double);
[17593]433    }
434
[17726]435
436    public virtual EvaluationResult Evaluate(IDataset dataset, ref int row, InterpreterState state,
437      IDictionary<ISymbolicExpressionTreeNode, EvaluationResult> traceDict = null) {
438
439      void TraceEvaluation(Instruction instr, EvaluationResult result) {
440        traceDict?.Add(instr.dynamicNode, result);
441      }
442
[5571]443      Instruction currentInstr = state.NextInstruction();
444      switch (currentInstr.opCode) {
445        case OpCodes.Add: {
[17726]446            var cur = Evaluate(dataset, ref row, state, traceDict);
[5571]447            for (int i = 1; i < currentInstr.nArguments; i++) {
[17726]448              var op = Evaluate(dataset, ref row, state, traceDict);
[17455]449              cur = ArithmeticApply(cur, op,
[17721]450                (lhs, rhs) => ApplyVectorLengthStrategy(DifferentVectorLengthStrategy, lhs, rhs, 0.0),
[17455]451                (s1, s2) => s1 + s2,
452                (s1, v2) => s1 + v2,
453                (v1, s2) => v1 + s2,
454                (v1, v2) => v1 + v2);
[5571]455            }
[17726]456            TraceEvaluation(currentInstr, cur);
[17455]457            return cur;
[5571]458          }
459        case OpCodes.Sub: {
[17726]460            var cur = Evaluate(dataset, ref row, state, traceDict);
[5571]461            for (int i = 1; i < currentInstr.nArguments; i++) {
[17726]462              var op = Evaluate(dataset, ref row, state, traceDict);
[17455]463              cur = ArithmeticApply(cur, op,
[17721]464                (lhs, rhs) => ApplyVectorLengthStrategy(DifferentVectorLengthStrategy, lhs, rhs, 0.0),
[17455]465                (s1, s2) => s1 - s2,
466                (s1, v2) => s1 - v2,
467                (v1, s2) => v1 - s2,
468                (v1, v2) => v1 - v2);
[5571]469            }
[17786]470            if (currentInstr.nArguments == 1)
471              cur = FunctionApply(cur,
472                s => -s,
473                v => -v);
[17726]474            TraceEvaluation(currentInstr, cur);
[17455]475            return cur;
[5571]476          }
477        case OpCodes.Mul: {
[17726]478            var cur = Evaluate(dataset, ref row, state, traceDict);
[5571]479            for (int i = 1; i < currentInstr.nArguments; i++) {
[17726]480              var op = Evaluate(dataset, ref row, state, traceDict);
[17455]481              cur = ArithmeticApply(cur, op,
[17721]482                (lhs, rhs) => ApplyVectorLengthStrategy(DifferentVectorLengthStrategy, lhs, rhs, 1.0),
[17455]483                (s1, s2) => s1 * s2,
484                (s1, v2) => s1 * v2,
485                (v1, s2) => v1 * s2,
486                (v1, v2) => v1.PointwiseMultiply(v2));
[5571]487            }
[17726]488            TraceEvaluation(currentInstr, cur);
[17455]489            return cur;
[5571]490          }
491        case OpCodes.Div: {
[17726]492            var cur = Evaluate(dataset, ref row, state, traceDict);
[5571]493            for (int i = 1; i < currentInstr.nArguments; i++) {
[17726]494              var op = Evaluate(dataset, ref row, state, traceDict);
[17455]495              cur = ArithmeticApply(cur, op,
[17721]496                (lhs, rhs) => ApplyVectorLengthStrategy(DifferentVectorLengthStrategy, lhs, rhs, 1.0),
[17455]497                (s1, s2) => s1 / s2,
498                (s1, v2) => s1 / v2,
499                (v1, s2) => v1 / s2,
500                (v1, v2) => v1 / v2);
[5571]501            }
[17786]502            if (currentInstr.nArguments == 1)
503              cur = FunctionApply(cur,
504                s => 1 / s,
505                v => 1 / v);
[17726]506            TraceEvaluation(currentInstr, cur);
[17455]507            return cur;
[5571]508          }
[16356]509        case OpCodes.Absolute: {
[17726]510            var cur = Evaluate(dataset, ref row, state, traceDict);
511            cur = FunctionApply(cur, Math.Abs, DoubleVector.Abs);
512            TraceEvaluation(currentInstr, cur);
513            return cur;
[16356]514          }
[16656]515        case OpCodes.Tanh: {
[17726]516            var cur = Evaluate(dataset, ref row, state, traceDict);
517            cur = FunctionApply(cur, Math.Tanh, DoubleVector.Tanh);
518            TraceEvaluation(currentInstr, cur);
519            return cur;
[16656]520          }
[5571]521        case OpCodes.Cos: {
[17726]522            var cur = Evaluate(dataset, ref row, state, traceDict);
523            cur = FunctionApply(cur, Math.Cos, DoubleVector.Cos);
524            TraceEvaluation(currentInstr, cur);
525            return cur;
[5571]526          }
527        case OpCodes.Sin: {
[17726]528            var cur = Evaluate(dataset, ref row, state, traceDict);
529            cur = FunctionApply(cur, Math.Sin, DoubleVector.Sin);
530            TraceEvaluation(currentInstr, cur);
531            return cur;
[5571]532          }
533        case OpCodes.Tan: {
[17726]534            var cur = Evaluate(dataset, ref row, state, traceDict);
535            cur = FunctionApply(cur, Math.Tan, DoubleVector.Tan);
536            TraceEvaluation(currentInstr, cur);
537            return cur;
[5571]538          }
[7842]539        case OpCodes.Square: {
[17726]540            var cur = Evaluate(dataset, ref row, state, traceDict);
541            cur = FunctionApply(cur,
[17455]542              s => Math.Pow(s, 2),
543              v => v.PointwisePower(2));
[17726]544            TraceEvaluation(currentInstr, cur);
545            return cur;
[7842]546          }
[16356]547        case OpCodes.Cube: {
[17726]548            var cur = Evaluate(dataset, ref row, state, traceDict);
549            cur = FunctionApply(cur,
[17455]550              s => Math.Pow(s, 3),
551              v => v.PointwisePower(3));
[17726]552            TraceEvaluation(currentInstr, cur);
553            return cur;
[16356]554          }
[5571]555        case OpCodes.Power: {
[17726]556            var x = Evaluate(dataset, ref row, state, traceDict);
557            var y = Evaluate(dataset, ref row, state, traceDict);
558            var cur = ArithmeticApply(x, y,
[17721]559              (lhs, rhs) => lhs.Count < rhs.Count
560                ? CutLonger(lhs, rhs)
561                : ApplyVectorLengthStrategy(DifferentVectorLengthStrategy, lhs, rhs, 1.0),
[17455]562              (s1, s2) => Math.Pow(s1, Math.Round(s2)),
563              (s1, v2) => DoubleVector.Build.Dense(v2.Count, s1).PointwisePower(DoubleVector.Round(v2)),
564              (v1, s2) => v1.PointwisePower(Math.Round(s2)),
565              (v1, v2) => v1.PointwisePower(DoubleVector.Round(v2)));
[17726]566            TraceEvaluation(currentInstr, cur);
567            return cur;
[5571]568          }
[7842]569        case OpCodes.SquareRoot: {
[17726]570            var cur = Evaluate(dataset, ref row, state, traceDict);
571            cur = FunctionApply(cur,
[17455]572              s => Math.Sqrt(s),
573              v => DoubleVector.Sqrt(v));
[17726]574            TraceEvaluation(currentInstr, cur);
575            return cur;
[7842]576          }
[16356]577        case OpCodes.CubeRoot: {
[17726]578            var cur = Evaluate(dataset, ref row, state, traceDict);
579            cur = FunctionApply(cur,
[17455]580              s => s < 0 ? -Math.Pow(-s, 1.0 / 3.0) : Math.Pow(s, 1.0 / 3.0),
581              v => v.Map(s => s < 0 ? -Math.Pow(-s, 1.0 / 3.0) : Math.Pow(s, 1.0 / 3.0)));
[17726]582            TraceEvaluation(currentInstr, cur);
583            return cur;
[16356]584          }
[5571]585        case OpCodes.Root: {
[17726]586            var x = Evaluate(dataset, ref row, state, traceDict);
587            var y = Evaluate(dataset, ref row, state, traceDict);
588            var cur = ArithmeticApply(x, y,
[17721]589              (lhs, rhs) => lhs.Count < rhs.Count
590                ? CutLonger(lhs, rhs)
591                : ApplyVectorLengthStrategy(DifferentVectorLengthStrategy, lhs, rhs, 1.0),
[17455]592              (s1, s2) => Math.Pow(s1, 1.0 / Math.Round(s2)),
593              (s1, v2) => DoubleVector.Build.Dense(v2.Count, s1).PointwisePower(1.0 / DoubleVector.Round(v2)),
594              (v1, s2) => v1.PointwisePower(1.0 / Math.Round(s2)),
595              (v1, v2) => v1.PointwisePower(1.0 / DoubleVector.Round(v2)));
[17726]596            TraceEvaluation(currentInstr, cur);
597            return cur;
[5571]598          }
599        case OpCodes.Exp: {
[17726]600            var cur = Evaluate(dataset, ref row, state, traceDict);
601            cur = FunctionApply(cur,
[17455]602              s => Math.Exp(s),
603              v => DoubleVector.Exp(v));
[17726]604            TraceEvaluation(currentInstr, cur);
605            return cur;
[5571]606          }
607        case OpCodes.Log: {
[17726]608            var cur = Evaluate(dataset, ref row, state, traceDict);
609            cur = FunctionApply(cur,
[17455]610              s => Math.Log(s),
611              v => DoubleVector.Log(v));
[17726]612            TraceEvaluation(currentInstr, cur);
613            return cur;
[5571]614          }
[17460]615        case OpCodes.Sum: {
[17726]616            var cur = Evaluate(dataset, ref row, state, traceDict);
617            cur = AggregateApply(cur,
[17460]618              s => s,
619              v => v.Sum());
[17726]620            TraceEvaluation(currentInstr, cur);
621            return cur;
[17460]622          }
[17466]623        case OpCodes.Mean: {
[17726]624            var cur = Evaluate(dataset, ref row, state, traceDict);
625            cur = AggregateApply(cur,
[17460]626              s => s,
[17721]627              v => Statistics.Mean(v));
[17726]628            TraceEvaluation(currentInstr, cur);
629            return cur;
[17460]630          }
[17463]631        case OpCodes.StandardDeviation: {
[17726]632            var cur = Evaluate(dataset, ref row, state, traceDict);
633            cur = AggregateApply(cur,
[17602]634              s => 0,
635              v => Statistics.PopulationStandardDeviation(v));
[17726]636            TraceEvaluation(currentInstr, cur);
637            return cur;
[17463]638          }
[17554]639        case OpCodes.Length: {
[17726]640            var cur = Evaluate(dataset, ref row, state, traceDict);
641            cur = AggregateApply(cur,
[17593]642              s => 1,
643              v => v.Count);
[17726]644            TraceEvaluation(currentInstr, cur);
645            return cur;
[17593]646          }
[17554]647        case OpCodes.Min: {
[17726]648            var cur = Evaluate(dataset, ref row, state, traceDict);
649            cur = AggregateApply(cur,
[17593]650              s => s,
651              v => Statistics.Minimum(v));
[17726]652            TraceEvaluation(currentInstr, cur);
653            return cur;
[17593]654          }
[17554]655        case OpCodes.Max: {
[17726]656            var cur = Evaluate(dataset, ref row, state, traceDict);
657            cur = AggregateApply(cur,
[17593]658              s => s,
659              v => Statistics.Maximum(v));
[17726]660            TraceEvaluation(currentInstr, cur);
661            return cur;
[17593]662          }
[17554]663        case OpCodes.Variance: {
[17726]664            var cur = Evaluate(dataset, ref row, state, traceDict);
665            cur = AggregateApply(cur,
[17602]666              s => 0,
667              v => Statistics.PopulationVariance(v));
[17726]668            TraceEvaluation(currentInstr, cur);
669            return cur;
[17593]670          }
[17554]671        case OpCodes.Skewness: {
[17726]672            var cur = Evaluate(dataset, ref row, state, traceDict);
673            cur = AggregateApply(cur,
[17593]674              s => double.NaN,
[17602]675              v => Statistics.PopulationSkewness(v));
[17726]676            TraceEvaluation(currentInstr, cur);
677            return cur;
[17593]678          }
[17554]679        case OpCodes.Kurtosis: {
[17726]680            var cur = Evaluate(dataset, ref row, state, traceDict);
681            cur = AggregateApply(cur,
[17593]682              s => double.NaN,
[17602]683              v => Statistics.PopulationKurtosis(v));
[17726]684            TraceEvaluation(currentInstr, cur);
685            return cur;
[17593]686          }
[17554]687        case OpCodes.EuclideanDistance: {
[17726]688            var x1 = Evaluate(dataset, ref row, state, traceDict);
689            var x2 = Evaluate(dataset, ref row, state, traceDict);
690            var cur = AggregateMultipleApply(x1, x2,
[17721]691              (lhs, rhs) => ApplyVectorLengthStrategy(DifferentVectorLengthStrategy, lhs, rhs, 0.0),
692              (s1, s2) => s1 - s2,
693              (s1, v2) => Math.Sqrt((s1 - v2).PointwisePower(2).Sum()),
694              (v1, s2) => Math.Sqrt((v1 - s2).PointwisePower(2).Sum()),
695              (v1, v2) => Math.Sqrt((v1 - v2).PointwisePower(2).Sum()));
[17726]696            TraceEvaluation(currentInstr, cur);
697            return cur;
[17593]698          }
[17554]699        case OpCodes.Covariance: {
[17726]700            var x1 = Evaluate(dataset, ref row, state, traceDict);
701            var x2 = Evaluate(dataset, ref row, state, traceDict);
702            var cur = AggregateMultipleApply(x1, x2,
[17721]703              (lhs, rhs) => ApplyVectorLengthStrategy(DifferentVectorLengthStrategy, lhs, rhs, 0.0),
704              (s1, s2) => 0,
705              (s1, v2) => 0,
706              (v1, s2) => 0,
707              (v1, v2) => Statistics.PopulationCovariance(v1, v2));
[17726]708            TraceEvaluation(currentInstr, cur);
709            return cur;
[17593]710          }
[17726]711        case OpCodes.SubVector: {
712            var cur = Evaluate(dataset, ref row, state, traceDict);
713            return WindowedFunctionApply(cur, (WindowedSymbolTreeNode)currentInstr.dynamicNode,
714              s => s,
715              v => v);
716          }
[5571]717        case OpCodes.Variable: {
[17455]718            if (row < 0 || row >= dataset.Rows) return EvaluationResult.NaN;
[6740]719            var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
[17726]720            if (currentInstr.data is IList<double> doubleList) {
721              var cur = new EvaluationResult(doubleList[row] * variableTreeNode.Weight);
722              TraceEvaluation(currentInstr, cur);
723              return cur;
724            }
725            if (currentInstr.data is IList<DoubleVector> doubleVectorList) {
726              var cur = new EvaluationResult(doubleVectorList[row] * variableTreeNode.Weight);
727              TraceEvaluation(currentInstr, cur);
728              return cur;
729            }
[17455]730            throw new NotSupportedException($"Unsupported type of variable: {currentInstr.data.GetType().GetPrettyName()}");
[5571]731          }
[14826]732        case OpCodes.BinaryFactorVariable: {
[17455]733            if (row < 0 || row >= dataset.Rows) return EvaluationResult.NaN;
[14826]734            var factorVarTreeNode = currentInstr.dynamicNode as BinaryFactorVariableTreeNode;
[17726]735            var cur = new EvaluationResult(((IList<string>)currentInstr.data)[row] == factorVarTreeNode.VariableValue ? factorVarTreeNode.Weight : 0);
736            TraceEvaluation(currentInstr, cur);
737            return cur;
[14826]738          }
739        case OpCodes.FactorVariable: {
[17455]740            if (row < 0 || row >= dataset.Rows) return EvaluationResult.NaN;
[14826]741            var factorVarTreeNode = currentInstr.dynamicNode as FactorVariableTreeNode;
[17726]742            var cur = new EvaluationResult(factorVarTreeNode.GetValue(((IList<string>)currentInstr.data)[row]));
743            TraceEvaluation(currentInstr, cur);
744            return cur;
[14826]745          }
[5571]746        case OpCodes.Constant: {
[8436]747            var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
[17726]748            var cur = new EvaluationResult(constTreeNode.Value);
749            TraceEvaluation(currentInstr, cur);
750            return cur;
[5571]751          }
752
[17830]753        #region Time Series Symbols
754        case OpCodes.Median: {
755            var cur = Evaluate(dataset, ref row, state, traceDict);
756            cur = AggregateApply(cur,
757              s => s,
758              v => Statistics.Median(v));
759            TraceEvaluation(currentInstr, cur);
760            return cur;
761          }
762        case OpCodes.Quantile: {
763            var cur = Evaluate(dataset, ref row, state, traceDict);
764            var q = Evaluate(dataset, ref row, state, traceDict);
765            cur = AggregateApply(cur,
766              s => s,
767              v => Statistics.Quantile(v, q.Scalar));
768            TraceEvaluation(currentInstr, cur);
769            return cur;
770          }
771
772        case OpCodes.AbsoluteEnergy: {
773            var cur = Evaluate(dataset, ref row, state, traceDict);
774            cur = AggregateApply(cur,
775              s => s * s,
776              v => v.PointwisePower(2.0).Sum());
777            TraceEvaluation(currentInstr, cur);
778            return cur;
779          }
780
781        case OpCodes.BinnedEntropy: {
782            var cur = Evaluate(dataset, ref row, state, traceDict);
783            var m = Evaluate(dataset, ref row, state, traceDict);
784            cur = AggregateApply(cur,
785              s => 0,
786              v => {
[17930]787                int bins = Math.Max((int)Math.Round(m.Scalar), 1);
[17830]788                double minValue = v.Minimum();
789                double maxValue = v.Maximum();
790                double intervalWidth = (maxValue - minValue) / bins;
791                int totalValues = v.Count;
792                double sum = 0;
793                for (int i = 0; i < Math.Max(bins, v.Count); i++) {
794                  double binMin = minValue * i;
795                  double binMax = binMin + intervalWidth;
[17930]796                  double countBin = v.Map(e => (e > binMin && e < binMax) ? 1.0 : 0.0).Sum();
[17830]797                  double percBin = countBin / totalValues;
798                  sum += percBin * Math.Log(percBin);
799                }
800
801                return sum;
802              });
803            TraceEvaluation(currentInstr, cur);
804            return cur;
805          }
806        case OpCodes.HasLargeStandardDeviation: {
807            var cur = Evaluate(dataset, ref row, state, traceDict);
808            cur = AggregateApply(cur,
809              s => 0,
[17930]810              v => Statistics.PopulationStandardDeviation(v) > (Statistics.Maximum(v) - Statistics.Minimum(v)) / 2 ? 1.0 : 0.0);
[17830]811            TraceEvaluation(currentInstr, cur);
812            return cur;
813          }
814        case OpCodes.HasVarianceLargerThanStd: {
815            var cur = Evaluate(dataset, ref row, state, traceDict);
816            cur = AggregateApply(cur,
817              s => 0,
[17930]818              v => Statistics.PopulationVariance(v) > Statistics.StandardDeviation(v) ? 1.0 : 0.0);
[17830]819            TraceEvaluation(currentInstr, cur);
820            return cur;
821          }
822        case OpCodes.IsSymmetricLooking: {
823            var cur = Evaluate(dataset, ref row, state, traceDict);
824            cur = AggregateApply(cur,
825              s => 0,
[17930]826              v => Math.Abs(Statistics.Mean(v) - Statistics.Median(v)) < (Statistics.Maximum(v) - Statistics.Minimum(v)) / 2 ? 1.0 : 0.0);
[17830]827            TraceEvaluation(currentInstr, cur);
828            return cur;
829          }
830        case OpCodes.NumberDataPointsAboveMean: {
831            var cur = Evaluate(dataset, ref row, state, traceDict);
832            cur = AggregateApply(cur,
833              s => 0,
834              v => {
835                double mean = Statistics.Mean(v);
[17930]836                return v.Map(e => e > mean ? 1.0 : 0.0).Sum();
[17830]837              });
838            TraceEvaluation(currentInstr, cur);
839            return cur;
840          }
841        case OpCodes.NumberDataPointsAboveMedian: {
842            var cur = Evaluate(dataset, ref row, state, traceDict);
843            cur = AggregateApply(cur,
844              s => 0,
845              v => {
846                double median = Statistics.Median(v);
[17930]847                return v.Map(e => e > median ? 1.0 : 0.0).Sum();
[17830]848              });
849            TraceEvaluation(currentInstr, cur);
850            return cur;
851          }
852        case OpCodes.NumberDataPointsBelowMean: {
853            var cur = Evaluate(dataset, ref row, state, traceDict);
854            cur = AggregateApply(cur,
855              s => 0,
856              v => {
857                double mean = Statistics.Mean(v);
[17930]858                return v.Map(e => e < mean ? 1.0 : 0.0).Sum();
[17830]859              });
860            TraceEvaluation(currentInstr, cur);
861            return cur;
862          }
863        case OpCodes.NumberDataPointsBelowMedian: {
864            var cur = Evaluate(dataset, ref row, state, traceDict);
865            cur = AggregateApply(cur,
866              s => 0,
867              v => {
868                double median = Statistics.Median(v);
[17930]869                return v.Map(e => e < median ? 1.0 : 0.0).Sum();
[17830]870              });
871            TraceEvaluation(currentInstr, cur);
872            return cur;
873          }
874
875        case OpCodes.ArimaModelCoefficients: {
876            var cur = Evaluate(dataset, ref row, state, traceDict);
877            var i = Evaluate(dataset, ref row, state, traceDict);
878            var k = Evaluate(dataset, ref row, state, traceDict);
879            cur = AggregateApply(cur,
880              s => 0,
881              v => throw new NotImplementedException(""));
882            TraceEvaluation(currentInstr, cur);
883            return cur;
884          }
885        case OpCodes.ContinuousWaveletTransformationCoefficients: {
886            var cur = Evaluate(dataset, ref row, state, traceDict);
887            var a = Evaluate(dataset, ref row, state, traceDict);
888            var b = Evaluate(dataset, ref row, state, traceDict);
889            cur = AggregateApply(cur,
890              s => 0,
891              v => throw new NotImplementedException(""));
892            TraceEvaluation(currentInstr, cur);
893            return cur;
894          }
895        case OpCodes.FastFourierTransformationCoefficient: {
896            var cur = Evaluate(dataset, ref row, state, traceDict);
897            var k = Evaluate(dataset, ref row, state, traceDict);
898            cur = AggregateApply(cur,
899              s => 0,
900              v => throw new NotImplementedException(""));
901            TraceEvaluation(currentInstr, cur);
902            return cur;
903          }
904        case OpCodes.FirstIndexMax: {
905            var cur = Evaluate(dataset, ref row, state, traceDict);
906            cur = AggregateApply(cur,
907              s => 0,
908              v => (double)v.MaximumIndex() / v.Count);
909            TraceEvaluation(currentInstr, cur);
910            return cur;
911          }
912        case OpCodes.FirstIndexMin: {
913            var cur = Evaluate(dataset, ref row, state, traceDict);
914            cur = AggregateApply(cur,
915              s => 0,
916              v => (double)v.MinimumIndex() / v.Count);
917            TraceEvaluation(currentInstr, cur);
918            return cur;
919          }
920        case OpCodes.LastIndexMax: {
921            var cur = Evaluate(dataset, ref row, state, traceDict);
922            cur = AggregateApply(cur,
923              s => 0,
924              v => (double)(v.Count - DoubleVector.Build.DenseOfEnumerable(v.Reverse()).MaximumIndex()) / v.Count);
925
926            TraceEvaluation(currentInstr, cur);
927            return cur;
928          }
929        case OpCodes.LastIndexMin: {
930            var cur = Evaluate(dataset, ref row, state, traceDict);
931            cur = AggregateApply(cur,
932              s => 0,
933              v => (double)(v.Count - DoubleVector.Build.DenseOfEnumerable(v.Reverse()).MinimumIndex()) / v.Count);
934            TraceEvaluation(currentInstr, cur);
935            return cur;
936          }
937        case OpCodes.LongestStrikeAboveMean: {
938            var cur = Evaluate(dataset, ref row, state, traceDict);
939            cur = AggregateApply(cur,
940              s => 0,
941              v => LongestStrikeAbove(v, Statistics.Mean(v)));
942            TraceEvaluation(currentInstr, cur);
943            return cur;
944          }
945        case OpCodes.LongestStrikeAboveMedian: {
946            var cur = Evaluate(dataset, ref row, state, traceDict);
947            cur = AggregateApply(cur,
948              s => 0,
949              v => LongestStrikeAbove(v, Statistics.Median(v)));
950            TraceEvaluation(currentInstr, cur);
951            return cur;
952          }
953        case OpCodes.LongestStrikeBelowMean: {
954            var cur = Evaluate(dataset, ref row, state, traceDict);
955            cur = AggregateApply(cur,
956              s => 0,
957              v => LongestStrikeBelow(v, Statistics.Mean(v)));
958            TraceEvaluation(currentInstr, cur);
959            return cur;
960          }
961        case OpCodes.LongestStrikeBelowMedian: {
962            var cur = Evaluate(dataset, ref row, state, traceDict);
963            cur = AggregateApply(cur,
964              s => 0,
965              v => LongestStrikeBelow(v, Statistics.Median(v)));
966            TraceEvaluation(currentInstr, cur);
967            return cur;
968          }
969        case OpCodes.LongestStrikePositive: {
970            var cur = Evaluate(dataset, ref row, state, traceDict);
971            cur = AggregateApply(cur,
972              s => 0,
973              v => LongestStrikeAbove(v, 0));
974            TraceEvaluation(currentInstr, cur);
975            return cur;
976          }
977        case OpCodes.LongestStrikeNegative: {
978            var cur = Evaluate(dataset, ref row, state, traceDict);
979            cur = AggregateApply(cur,
980              s => 0,
981              v => LongestStrikeAbove(v, 0));
982            TraceEvaluation(currentInstr, cur);
983            return cur;
984          }
985        case OpCodes.LongestStrikeZero: {
986            var cur = Evaluate(dataset, ref row, state, traceDict);
987            cur = AggregateApply(cur,
988              s => 0,
989              v => LongestStrikeEqual(v, 0));
990            TraceEvaluation(currentInstr, cur);
991            return cur;
992          }
993        case OpCodes.MeanAbsoluteChange: {
994            var cur = Evaluate(dataset, ref row, state, traceDict);
995            cur = AggregateApply(cur,
996              s => 0,
997              v => {
998                double sum = 0.0;
999                for (int i = 0; i < v.Count - 1; i++) {
1000                  sum += Math.Abs(v[i + 1] - v[i]);
1001                }
1002
1003                return sum / v.Count;
1004              });
1005            TraceEvaluation(currentInstr, cur);
1006            return cur;
1007          }
1008        case OpCodes.MeanAbsoluteChangeQuantiles: {
1009            var cur = Evaluate(dataset, ref row, state, traceDict);
1010            var ql = Evaluate(dataset, ref row, state, traceDict);
1011            var qu = Evaluate(dataset, ref row, state, traceDict);
1012            cur = AggregateApply(cur,
1013              s => 0,
1014              v => {
1015                var lowerBound = Statistics.Quantile(v, ql.Scalar);
1016                var upperBound = Statistics.Quantile(v, qu.Scalar);
1017                var inBounds = v.Select(e => e > lowerBound && e < upperBound).ToList();
1018                double sum = 0.0;
1019                int count = 0;
1020                for (int i = 0; i < v.Count - 1; i++) {
1021                  if (inBounds[i] && inBounds[i + 1]) {
1022                    sum += Math.Abs(v[i + 1] - v[i]);
1023                    count++;
1024                  }
1025                }
1026
1027                return sum / count;
1028              });
1029            TraceEvaluation(currentInstr, cur);
1030            return cur;
1031          }
1032        case OpCodes.MeanAutocorrelation: {
1033            var cur = Evaluate(dataset, ref row, state, traceDict);
1034            cur = AggregateApply(cur,
1035              s => 0,
1036              v => {
1037                double sum = 0.0;
1038                double mean = Statistics.Mean(v);
1039                for (int l = 0; l < v.Count; l++) {
1040                  for (int i = 0; i < v.Count - l; i++) {
1041                    sum += (v[i] - mean) * (v[i + l] - mean);
1042                  }
1043                }
1044
1045                return sum / (v.Count - 1) / Statistics.PopulationVariance(v);
1046              });
1047            TraceEvaluation(currentInstr, cur);
1048            return cur;
1049          }
1050        case OpCodes.LaggedAutocorrelation: {
1051            var cur = Evaluate(dataset, ref row, state, traceDict);
1052            var lVal = Evaluate(dataset, ref row, state, traceDict);
1053            cur = AggregateApply(cur,
1054              s => 0,
1055              v => {
1056                double sum = 0.0;
[17930]1057                int l = Math.Max((int)Math.Round(lVal.Scalar), 0);
[17830]1058                double mean = Statistics.Mean(v);
1059                for (int i = 0; i < v.Count - l; i++) {
1060                  sum += (v[i] - mean) * (v[i + l] - mean);
1061                }
1062
1063                return sum / Statistics.PopulationVariance(v);
1064              });
1065            TraceEvaluation(currentInstr, cur);
1066            return cur;
1067          }
1068        case OpCodes.MeanSecondDerivateCentral: {
1069            var cur = Evaluate(dataset, ref row, state, traceDict);
1070            cur = AggregateApply(cur,
1071              s => 0,
1072              v => {
1073                double sum = 0.0;
1074                for (int i = 1; i < v.Count - 1; i++) {
1075                  sum += (v[i - 1] - 2 * v[i] + v[i + 1]) / 2;
1076                }
1077
1078                return sum / (v.Count - 2);
1079              });
1080            TraceEvaluation(currentInstr, cur);
1081            return cur;
1082          }
1083        case OpCodes.NumberPeaksOfSize: {
1084            var cur = Evaluate(dataset, ref row, state, traceDict);
1085            var l = Evaluate(dataset, ref row, state, traceDict);
1086            cur = AggregateApply(cur,
1087              s => 0,
1088              v => CountNumberOfPeaks(v, l.Scalar));
1089            TraceEvaluation(currentInstr, cur);
1090            return cur;
1091          }
1092        case OpCodes.LargeNumberOfPeaks: {
1093            var cur = Evaluate(dataset, ref row, state, traceDict);
1094            var l = Evaluate(dataset, ref row, state, traceDict);
1095            var m = Evaluate(dataset, ref row, state, traceDict);
1096            cur = AggregateApply(cur,
1097              s => 0,
1098              v => CountNumberOfPeaks(v, l.Scalar) > m.Scalar ? 1.0 : 0.0);
1099            TraceEvaluation(currentInstr, cur);
1100            return cur;
1101          }
1102        case OpCodes.TimeReversalAsymmetryStatistic: {
1103            var cur = Evaluate(dataset, ref row, state, traceDict);
1104            var l = Evaluate(dataset, ref row, state, traceDict);
1105            cur = AggregateApply(cur,
1106              s => 0,
1107              v => {
[17930]1108                int lag = Math.Max((int)Math.Round(l.Scalar), 0);
[17830]1109                double sum = 0.0;
1110                for (int i = 0; i < v.Count - 2 * lag; i++) {
1111                  sum += Math.Pow(v[i + 2 * lag], 2) * v[i + lag] - v[i + lag] * Math.Pow(v[i], 2);
1112                }
1113
1114                return sum / (v.Count - 2 * lag);
1115              });
1116            TraceEvaluation(currentInstr, cur);
1117            return cur;
1118          }
1119        #endregion
1120
[13248]1121        default:
[17455]1122          throw new NotSupportedException($"Unsupported OpCode: {currentInstr.opCode}");
[5571]1123      }
1124    }
[17830]1125
1126    private static int LongestStrikeAbove(DoubleVector v, double threshold) {
1127      int longestStrike = 0, currentStrike = 0;
1128      for (int i = 0; i < v.Count; i++) {
1129        if (v[i] > threshold) {
1130          currentStrike++;
1131          longestStrike = Math.Max(longestStrike, currentStrike);
1132        } else
1133          currentStrike = 0;
1134      }
1135      return longestStrike;
1136    }
1137    private static int LongestStrikeBelow(DoubleVector v, double threshold) {
1138      int longestStrike = 0, currentStrike = 0;
1139      for (int i = 0; i < v.Count; i++) {
1140        if (v[i] < threshold) {
1141          currentStrike++;
1142          longestStrike = Math.Max(longestStrike, currentStrike);
1143        } else
1144          currentStrike = 0;
1145      }
1146      return longestStrike;
1147    }
1148
1149    private static int LongestStrikeEqual(DoubleVector v, double value, double epsilon = double.Epsilon) {
1150      int longestStrike = 0, currentStrike = 0;
1151      for (int i = 0; i < v.Count; i++) {
1152        if (v[i].IsAlmost(epsilon)) {
1153          currentStrike++;
1154          longestStrike = Math.Max(longestStrike, currentStrike);
1155        } else
1156          currentStrike = 0;
1157      }
1158      return longestStrike;
1159    }
1160    private static int CountNumberOfPeaks(DoubleVector v, double heightDifference) {
1161      int count = 0;
1162      for (int i = 0; i < v.Count; i++) {
1163        bool largerThanPrev = i == 0 || v[i] > v[i - 1] + heightDifference;
1164        bool largerThanNext = i == v.Count - 1 || v[i] > v[i + 1] + heightDifference;
1165        if (largerThanPrev && largerThanNext)
1166          count++;
1167      }
1168      return count;
1169    }
[5571]1170  }
[13248]1171}
Note: See TracBrowser for help on using the repository browser.