#region License Information /* HeuristicLab * Copyright (C) 2002-2011 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.Drawing; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis { /// /// Represents a symbolic time-series prognosis model /// [StorableClass] [Item(Name = "Symbolic Time-Series Prognosis Model", Description = "Represents a symbolic time series prognosis model.")] public class SymbolicTimeSeriesPrognosisModel : NamedItem, ISymbolicTimeSeriesPrognosisModel { public override Image ItemImage { get { return HeuristicLab.Common.Resources.VSImageLibrary.Function; } } [Storable(DefaultValue = double.MinValue)] private double lowerEstimationLimit; [Storable(DefaultValue = double.MaxValue)] private double upperEstimationLimit; #region properties [Storable] private ISymbolicExpressionTree symbolicExpressionTree; public ISymbolicExpressionTree SymbolicExpressionTree { get { return symbolicExpressionTree; } } [Storable] private ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter; public ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter Interpreter { get { return interpreter; } } ISymbolicDataAnalysisExpressionTreeInterpreter ISymbolicDataAnalysisModel.Interpreter { get { return (ISymbolicDataAnalysisExpressionTreeInterpreter)interpreter; } } #endregion [Storable] private string[] targetVariables; [StorableConstructor] protected SymbolicTimeSeriesPrognosisModel(bool deserializing) : base(deserializing) { } protected SymbolicTimeSeriesPrognosisModel(SymbolicTimeSeriesPrognosisModel original, Cloner cloner) : base(original, cloner) { this.symbolicExpressionTree = cloner.Clone(original.symbolicExpressionTree); this.interpreter = cloner.Clone(original.interpreter); this.targetVariables = new string[original.targetVariables.Length]; Array.Copy(original.targetVariables, this.targetVariables, this.targetVariables.Length); this.lowerEstimationLimit = original.lowerEstimationLimit; this.upperEstimationLimit = original.upperEstimationLimit; } public SymbolicTimeSeriesPrognosisModel(ISymbolicExpressionTree tree, ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, IEnumerable targetVariables, double lowerLimit = double.MinValue, double upperLimit = double.MaxValue) : base() { this.name = ItemName; this.description = ItemDescription; this.symbolicExpressionTree = tree; this.interpreter = interpreter; this.targetVariables = targetVariables.ToArray(); this.lowerEstimationLimit = lowerLimit; this.upperEstimationLimit = upperLimit; } public override IDeepCloneable Clone(Cloner cloner) { return new SymbolicTimeSeriesPrognosisModel(this, cloner); } public IEnumerable>> GetPrognosedValues(Dataset dataset, IEnumerable rows, int horizon) { var enumerator = Interpreter.GetSymbolicExpressionTreeValues(SymbolicExpressionTree, dataset, targetVariables, rows, horizon). GetEnumerator(); foreach (var r in rows) { var l = new List(); for (int h = 0; h < horizon; h++) { double[] components = new double[targetVariables.Length]; for (int c = 0; c < components.Length; c++) { enumerator.MoveNext(); components[c] = Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, enumerator.Current)); } l.Add(components); } yield return l; } } public ISymbolicTimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData) { return new SymbolicTimeSeriesPrognosisSolution(this, problemData); } ITimeSeriesPrognosisSolution ITimeSeriesPrognosisModel.CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData) { return CreateTimeSeriesPrognosisSolution(problemData); } public static void Scale(SymbolicTimeSeriesPrognosisModel model, ITimeSeriesPrognosisProblemData problemData) { var dataset = problemData.Dataset; var targetVariables = problemData.TargetVariables.ToArray(); var rows = problemData.TrainingIndizes; var estimatedValuesEnumerator = model.Interpreter.GetSymbolicExpressionTreeValues(model.SymbolicExpressionTree, dataset, targetVariables, rows).GetEnumerator(); var scalingParameterCalculators = problemData.TargetVariables.Select(v => new OnlineLinearScalingParameterCalculator()).ToArray(); var targetValuesEnumerator = problemData.Dataset.GetVectorEnumerable(targetVariables, rows).GetEnumerator(); var more = targetValuesEnumerator.MoveNext() & estimatedValuesEnumerator.MoveNext(); // foreach row while (more) { // foreach component for (int i = 0; i < targetVariables.Length; i++) { scalingParameterCalculators[i].Add(estimatedValuesEnumerator.Current, targetValuesEnumerator.Current); more = estimatedValuesEnumerator.MoveNext() & targetValuesEnumerator.MoveNext(); } } for (int i = 0; i < targetVariables.Count(); i++) { if (scalingParameterCalculators[i].ErrorState != OnlineCalculatorError.None) continue; double alpha = scalingParameterCalculators[i].Alpha; double beta = scalingParameterCalculators[i].Beta; ConstantTreeNode alphaTreeNode = null; ConstantTreeNode betaTreeNode = null; // check if model has been scaled previously by analyzing the structure of the tree var startNode = model.SymbolicExpressionTree.Root.GetSubtree(0); if (startNode.GetSubtree(i).Symbol is Addition) { var addNode = startNode.GetSubtree(i); if (addNode.SubtreeCount == 2 && addNode.GetSubtree(0).Symbol is Multiplication && addNode.GetSubtree(1).Symbol is Constant) { alphaTreeNode = addNode.GetSubtree(1) as ConstantTreeNode; var mulNode = addNode.GetSubtree(0); if (mulNode.SubtreeCount == 2 && mulNode.GetSubtree(1).Symbol is Constant) { betaTreeNode = mulNode.GetSubtree(1) as ConstantTreeNode; } } } // if tree structure matches the structure necessary for linear scaling then reuse the existing tree nodes if (alphaTreeNode != null && betaTreeNode != null) { betaTreeNode.Value *= beta; alphaTreeNode.Value *= beta; alphaTreeNode.Value += alpha; } else { var mainBranch = startNode.GetSubtree(i); startNode.RemoveSubtree(i); var scaledMainBranch = MakeSum(MakeProduct(mainBranch, beta), alpha); startNode.InsertSubtree(i, scaledMainBranch); } } // foreach } private static ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode treeNode, double alpha) { if (alpha.IsAlmost(0.0)) { return treeNode; } else { var addition = new Addition(); var node = addition.CreateTreeNode(); var alphaConst = MakeConstant(alpha); node.AddSubtree(treeNode); node.AddSubtree(alphaConst); return node; } } private static ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode treeNode, double beta) { if (beta.IsAlmost(1.0)) { return treeNode; } else { var multipliciation = new Multiplication(); var node = multipliciation.CreateTreeNode(); var betaConst = MakeConstant(beta); node.AddSubtree(treeNode); node.AddSubtree(betaConst); return node; } } private static ISymbolicExpressionTreeNode MakeConstant(double c) { var node = (ConstantTreeNode)(new Constant()).CreateTreeNode(); node.Value = c; return node; } } }