Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.TimeSeries/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModel.cs @ 8477

Last change on this file since 8477 was 8477, checked in by mkommend, 12 years ago

#1081:

  • Added autoregressive target variable Symbol
  • Merged trunk changes into the branch.
File size: 10.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28using HeuristicLab.Problems.DataAnalysis;
29
30namespace HeuristicLab.Algorithms.DataAnalysis {
31  /// <summary>
32  /// Represents a Gaussian process model.
33  /// </summary>
34  [StorableClass]
35  [Item("GaussianProcessModel", "Represents a Gaussian process posterior.")]
36  public sealed class GaussianProcessModel : NamedItem, IGaussianProcessModel {
37    [Storable]
38    private double negativeLogLikelihood;
39    public double NegativeLogLikelihood {
40      get { return negativeLogLikelihood; }
41    }
42
43    [Storable]
44    private ICovarianceFunction covarianceFunction;
45    public ICovarianceFunction CovarianceFunction {
46      get { return covarianceFunction; }
47    }
48    [Storable]
49    private IMeanFunction meanFunction;
50    public IMeanFunction MeanFunction {
51      get { return meanFunction; }
52    }
53    [Storable]
54    private string targetVariable;
55    public string TargetVariable {
56      get { return targetVariable; }
57    }
58    [Storable]
59    private string[] allowedInputVariables;
60    public string[] AllowedInputVariables {
61      get { return allowedInputVariables; }
62    }
63
64    [Storable]
65    private double[] alpha;
66    [Storable]
67    private double sqrSigmaNoise;
68
69    [Storable]
70    private double[,] l;
71
72    [Storable]
73    private double[,] x;
74    [Storable]
75    private Scaling inputScaling;
76
77
78    [StorableConstructor]
79    private GaussianProcessModel(bool deserializing) : base(deserializing) { }
80    private GaussianProcessModel(GaussianProcessModel original, Cloner cloner)
81      : base(original, cloner) {
82      this.meanFunction = cloner.Clone(original.meanFunction);
83      this.covarianceFunction = cloner.Clone(original.covarianceFunction);
84      this.inputScaling = cloner.Clone(original.inputScaling);
85      this.negativeLogLikelihood = original.negativeLogLikelihood;
86      this.targetVariable = original.targetVariable;
87      this.sqrSigmaNoise = original.sqrSigmaNoise;
88
89      // shallow copies of arrays because they cannot be modified
90      this.allowedInputVariables = original.allowedInputVariables;
91      this.alpha = original.alpha;
92      this.l = original.l;
93      this.x = original.x;
94    }
95    public GaussianProcessModel(Dataset ds, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows,
96      IEnumerable<double> hyp, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction)
97      : base() {
98      this.name = ItemName;
99      this.description = ItemDescription;
100      this.meanFunction = (IMeanFunction)meanFunction.Clone();
101      this.covarianceFunction = (ICovarianceFunction)covarianceFunction.Clone();
102      this.targetVariable = targetVariable;
103      this.allowedInputVariables = allowedInputVariables.ToArray();
104
105
106      int nVariables = this.allowedInputVariables.Length;
107      this.meanFunction.SetParameter(hyp
108        .Take(this.meanFunction.GetNumberOfParameters(nVariables))
109        .ToArray());
110      this.covarianceFunction.SetParameter(hyp.Skip(this.meanFunction.GetNumberOfParameters(nVariables))
111        .Take(this.covarianceFunction.GetNumberOfParameters(nVariables))
112        .ToArray());
113      sqrSigmaNoise = Math.Exp(2.0 * hyp.Last());
114
115      CalculateModel(ds, rows);
116    }
117
118    private void CalculateModel(Dataset ds, IEnumerable<int> rows) {
119      inputScaling = new Scaling(ds, allowedInputVariables, rows);
120      x = AlglibUtil.PrepareAndScaleInputMatrix(ds, allowedInputVariables, rows, inputScaling);
121      var y = ds.GetDoubleValues(targetVariable, rows);
122
123      int n = x.GetLength(0);
124      l = new double[n, n];
125
126      meanFunction.SetData(x);
127      covarianceFunction.SetData(x);
128
129      // calculate means and covariances
130      double[] m = meanFunction.GetMean(x);
131      for (int i = 0; i < n; i++) {
132        for (int j = i; j < n; j++) {
133          l[j, i] = covarianceFunction.GetCovariance(i, j) / sqrSigmaNoise;
134          if (j == i) l[j, i] += 1.0;
135        }
136      }
137
138      // cholesky decomposition
139      int info;
140      alglib.densesolverreport denseSolveRep;
141
142      var res = alglib.trfac.spdmatrixcholesky(ref l, n, false);
143      if (!res) throw new ArgumentException("Matrix is not positive semidefinite");
144
145      // calculate sum of diagonal elements for likelihood
146      double diagSum = Enumerable.Range(0, n).Select(i => Math.Log(l[i, i])).Sum();
147
148      // solve for alpha
149      double[] ym = y.Zip(m, (a, b) => a - b).ToArray();
150
151      alglib.spdmatrixcholeskysolve(l, n, false, ym, out info, out denseSolveRep, out alpha);
152      for (int i = 0; i < alpha.Length; i++)
153        alpha[i] = alpha[i] / sqrSigmaNoise;
154      negativeLogLikelihood = 0.5 * Util.ScalarProd(ym, alpha) + diagSum + (n / 2.0) * Math.Log(2.0 * Math.PI * sqrSigmaNoise);
155    }
156
157    public double[] GetHyperparameterGradients() {
158      // derivatives
159      int n = x.GetLength(0);
160      int nAllowedVariables = x.GetLength(1);
161
162      int info;
163      alglib.matinvreport matInvRep;
164      double[,] lCopy = new double[l.GetLength(0), l.GetLength(1)];
165      Array.Copy(l, lCopy, lCopy.Length);
166
167      alglib.spdmatrixcholeskyinverse(ref lCopy, n, false, out info, out matInvRep);
168      if (info != 1) throw new ArgumentException("Can't invert matrix to calculate gradients.");
169      for (int i = 0; i < n; i++) {
170        for (int j = 0; j <= i; j++)
171          lCopy[i, j] = lCopy[i, j] / sqrSigmaNoise - alpha[i] * alpha[j];
172      }
173
174      double noiseGradient = sqrSigmaNoise * Enumerable.Range(0, n).Select(i => lCopy[i, i]).Sum();
175
176      double[] meanGradients = new double[meanFunction.GetNumberOfParameters(nAllowedVariables)];
177      for (int i = 0; i < meanGradients.Length; i++) {
178        var meanGrad = meanFunction.GetGradients(i, x);
179        meanGradients[i] = -Util.ScalarProd(meanGrad, alpha);
180      }
181
182      double[] covGradients = new double[covarianceFunction.GetNumberOfParameters(nAllowedVariables)];
183      if (covGradients.Length > 0) {
184        for (int i = 0; i < n; i++) {
185          for (int k = 0; k < covGradients.Length; k++) {
186            for (int j = 0; j < i; j++) {
187              covGradients[k] += lCopy[i, j] * covarianceFunction.GetGradient(i, j, k);
188            }
189            covGradients[k] += 0.5 * lCopy[i, i] * covarianceFunction.GetGradient(i, i, k);
190          }
191        }
192      }
193
194      return
195        meanGradients
196        .Concat(covGradients)
197        .Concat(new double[] { noiseGradient }).ToArray();
198    }
199
200
201    public override IDeepCloneable Clone(Cloner cloner) {
202      return new GaussianProcessModel(this, cloner);
203    }
204
205    #region IRegressionModel Members
206    public IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows) {
207      return GetEstimatedValuesHelper(dataset, rows);
208    }
209    public GaussianProcessRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
210      return new GaussianProcessRegressionSolution(this, problemData);
211    }
212    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
213      return CreateRegressionSolution(problemData);
214    }
215    #endregion
216
217    private IEnumerable<double> GetEstimatedValuesHelper(Dataset dataset, IEnumerable<int> rows) {
218      var newX = AlglibUtil.PrepareAndScaleInputMatrix(dataset, allowedInputVariables, rows, inputScaling);
219      int newN = newX.GetLength(0);
220      int n = x.GetLength(0);
221      // var predMean = new double[newN];
222      // predVar = new double[newN];
223
224
225
226      // var kss = new double[newN];
227      var Ks = new double[newN, n];
228      //double[,] sWKs = new double[n, newN];
229      // double[,] v;
230
231
232      // for stddev
233      //covarianceFunction.SetParameter(covHyp, newX);
234      //kss = covarianceFunction.GetDiagonalCovariances();
235
236      covarianceFunction.SetData(x, newX);
237      meanFunction.SetData(newX);
238      var ms = meanFunction.GetMean(newX);
239      for (int i = 0; i < newN; i++) {
240        for (int j = 0; j < n; j++) {
241          Ks[i, j] = covarianceFunction.GetCovariance(j, i);
242          //sWKs[j, i] = Ks[i, j] / Math.Sqrt(sqrSigmaNoise);
243        }
244      }
245
246      // for stddev
247      // alglib.rmatrixsolvem(l, n, sWKs, newN, true, out info, out denseSolveRep, out v);
248
249      return Enumerable.Range(0, newN)
250        .Select(i => ms[i] + Util.ScalarProd(Util.GetRow(Ks, i), alpha));
251      //for (int i = 0; i < newN; i++) {
252      //  // predMean[i] = ms[i] + prod(GetRow(Ks, i), alpha);
253      //  // var sumV2 = prod(GetCol(v, i), GetCol(v, i));
254      //  // predVar[i] = kss[i] - sumV2;
255      //}
256
257    }
258
259    public IEnumerable<double> GetEstimatedVariance(Dataset dataset, IEnumerable<int> rows) {
260      var newX = AlglibUtil.PrepareAndScaleInputMatrix(dataset, allowedInputVariables, rows, inputScaling);
261      int newN = newX.GetLength(0);
262      int n = x.GetLength(0);
263
264      var kss = new double[newN];
265      double[,] sWKs = new double[n, newN];
266
267      // for stddev
268      covarianceFunction.SetData(newX);
269      for (int i = 0; i < newN; i++)
270        kss[i] = covarianceFunction.GetCovariance(i, i);
271
272      covarianceFunction.SetData(x, newX);
273      for (int i = 0; i < newN; i++) {
274        for (int j = 0; j < n; j++) {
275          sWKs[j, i] = covarianceFunction.GetCovariance(j, i) / Math.Sqrt(sqrSigmaNoise);
276        }
277      }
278
279      // for stddev
280      int info;
281      alglib.densesolverreport denseSolveRep;
282      double[,] v;
283
284      alglib.rmatrixsolvem(l, n, sWKs, newN, false, out info, out denseSolveRep, out v);
285
286      for (int i = 0; i < newN; i++) {
287        var sumV = Util.ScalarProd(Util.GetCol(v, i), Util.GetCol(v, i));
288        kss[i] -= sumV;
289        if (kss[i] < 0) kss[i] = 0;
290      }
291      return kss;
292    }
293  }
294}
Note: See TracBrowser for help on using the repository browser.