1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Linq;
|
---|
4 | using System.Text;
|
---|
5 | using HeuristicLab.Core;
|
---|
6 | using HeuristicLab.Data;
|
---|
7 | using HeuristicLab.Problems.DataAnalysis.Evaluators;
|
---|
8 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
9 | using HeuristicLab.Parameters;
|
---|
10 |
|
---|
11 | namespace HeuristicLab.Problems.DataAnalysis.MultiVariate.Evaluators {
|
---|
12 | public class OnlineMeanMahalanobisDistanceEvaluator : IMultiVariateOnlineEvaluator {
|
---|
13 | private int n;
|
---|
14 | private double distance;
|
---|
15 | private double[,] covMatrix;
|
---|
16 | private double[] diff;
|
---|
17 | private double[] target;
|
---|
18 | public double MeanMahalanobisDistance {
|
---|
19 | get {
|
---|
20 | if (n == 0) throw new InvalidOperationException("no elements");
|
---|
21 | else
|
---|
22 | return Math.Sqrt(distance) / n;
|
---|
23 | }
|
---|
24 | }
|
---|
25 |
|
---|
26 | public double MeanGeneralizedSquaredInterpointDistance {
|
---|
27 | get {
|
---|
28 | if (n == 0) throw new InvalidOperationException("no elements");
|
---|
29 | else
|
---|
30 | return distance / n;
|
---|
31 | }
|
---|
32 | }
|
---|
33 |
|
---|
34 | public OnlineMeanMahalanobisDistanceEvaluator() {
|
---|
35 | Reset();
|
---|
36 | }
|
---|
37 |
|
---|
38 | #region IMultiVariateOnlineEvaluator Members
|
---|
39 | public double Value {
|
---|
40 | get { return MeanMahalanobisDistance; }
|
---|
41 | }
|
---|
42 |
|
---|
43 | public void Add(IEnumerable<double> original, IEnumerable<double> estimated) {
|
---|
44 | if (covMatrix == null) throw new InvalidOperationException("Covariance matrix must be initialized before values can be added.");
|
---|
45 |
|
---|
46 | {
|
---|
47 | // calculate difference vector
|
---|
48 | var originalEnumerator = original.GetEnumerator();
|
---|
49 | var estimatedEnumerator = estimated.GetEnumerator();
|
---|
50 | int i = 0;
|
---|
51 | while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext() && i < diff.Length) {
|
---|
52 | diff[i++] = originalEnumerator.Current - estimatedEnumerator.Current;
|
---|
53 | }
|
---|
54 | if (originalEnumerator.MoveNext() | estimatedEnumerator.MoveNext() || i < diff.Length) {
|
---|
55 | throw new ArgumentException("Number of elements of original and estimated doesn't match or is not compatible with covariance matrix.");
|
---|
56 | }
|
---|
57 | }
|
---|
58 |
|
---|
59 | {
|
---|
60 | // calculate mahalanobis distance using covariance matrix
|
---|
61 | // covMatrix^(-1) * diff => target
|
---|
62 | alglib.ablas.rmatrixmv(covMatrix.GetLength(0), covMatrix.GetLength(1), covMatrix, 0, 0, 0, diff, 0, ref target, 0);
|
---|
63 |
|
---|
64 | // diff^T * (covMatrix^(-1) * diff) => sum
|
---|
65 | double sum = 0.0;
|
---|
66 | for (int i = 0; i < diff.Length; i++) {
|
---|
67 | sum += diff[i] * target[i];
|
---|
68 | }
|
---|
69 | distance += sum;
|
---|
70 | n++;
|
---|
71 | }
|
---|
72 | }
|
---|
73 |
|
---|
74 | public void Reset() {
|
---|
75 | n = 0;
|
---|
76 | distance = 0.0;
|
---|
77 | covMatrix = null;
|
---|
78 | diff = null;
|
---|
79 | target = null;
|
---|
80 | }
|
---|
81 |
|
---|
82 | #endregion
|
---|
83 |
|
---|
84 | public void InitializeCovarianceMatrixFromSamples(params IEnumerable<double>[] samples) {
|
---|
85 | covMatrix = new double[samples.Length, samples.Length];
|
---|
86 | OnlineCovarianceEvaluator covEvaluator = new OnlineCovarianceEvaluator();
|
---|
87 | for (int i = 0; i < samples.Length; i++) {
|
---|
88 | for (int j = i; j < samples.Length; j++) {
|
---|
89 | var xEnumerator = samples[i].GetEnumerator();
|
---|
90 | var yEnumerator = samples[j].GetEnumerator();
|
---|
91 | covEvaluator.Reset();
|
---|
92 | while (xEnumerator.MoveNext() & yEnumerator.MoveNext()) {
|
---|
93 | covEvaluator.Add(xEnumerator.Current, yEnumerator.Current);
|
---|
94 | }
|
---|
95 | if (xEnumerator.MoveNext() | yEnumerator.MoveNext()) {
|
---|
96 | throw new ArgumentException("Number of elements must be the same in all enumerations.");
|
---|
97 | }
|
---|
98 | covMatrix[i, j] = covEvaluator.Covariance;
|
---|
99 | covMatrix[j, i] = covEvaluator.Covariance;
|
---|
100 | }
|
---|
101 | }
|
---|
102 | int info = 0;
|
---|
103 | alglib.matinv.matinvreport report = new alglib.matinv.matinvreport();
|
---|
104 | alglib.matinv.rmatrixinverse(ref covMatrix, covMatrix.GetLength(0), ref info, report);
|
---|
105 | if (info != 1) throw new InvalidOperationException("Can't invert covariance matrix.");
|
---|
106 | diff = new double[samples.Length];
|
---|
107 | target = new double[samples.Length];
|
---|
108 | }
|
---|
109 | }
|
---|
110 | }
|
---|