source: src/main/java/agents/anac/y2019/harddealer/math3/distribution/MultivariateNormalDistribution.java

Last change on this file was 204, checked in by Katsuhide Fujita, 5 years ago

Fixed errors of ANAC2019 agents

  • Property svn:executable set to *
File size: 9.3 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package agents.anac.y2019.harddealer.math3.distribution;
18
19import agents.anac.y2019.harddealer.math3.exception.DimensionMismatchException;
20import agents.anac.y2019.harddealer.math3.linear.Array2DRowRealMatrix;
21import agents.anac.y2019.harddealer.math3.linear.EigenDecomposition;
22import agents.anac.y2019.harddealer.math3.linear.NonPositiveDefiniteMatrixException;
23import agents.anac.y2019.harddealer.math3.linear.RealMatrix;
24import agents.anac.y2019.harddealer.math3.linear.SingularMatrixException;
25import agents.anac.y2019.harddealer.math3.random.RandomGenerator;
26import agents.anac.y2019.harddealer.math3.random.Well19937c;
27import agents.anac.y2019.harddealer.math3.util.FastMath;
28import agents.anac.y2019.harddealer.math3.util.MathArrays;
29
30/**
31 * Implementation of the multivariate normal (Gaussian) distribution.
32 *
33 * @see <a href="http://en.wikipedia.org/wiki/Multivariate_normal_distribution">
34 * Multivariate normal distribution (Wikipedia)</a>
35 * @see <a href="http://mathworld.wolfram.com/MultivariateNormalDistribution.html">
36 * Multivariate normal distribution (MathWorld)</a>
37 *
38 * @since 3.1
39 */
40public class MultivariateNormalDistribution
41 extends AbstractMultivariateRealDistribution {
42 /** Vector of means. */
43 private final double[] means;
44 /** Covariance matrix. */
45 private final RealMatrix covarianceMatrix;
46 /** The matrix inverse of the covariance matrix. */
47 private final RealMatrix covarianceMatrixInverse;
48 /** The determinant of the covariance matrix. */
49 private final double covarianceMatrixDeterminant;
50 /** Matrix used in computation of samples. */
51 private final RealMatrix samplingMatrix;
52
53 /**
54 * Creates a multivariate normal distribution with the given mean vector and
55 * covariance matrix.
56 * <br/>
57 * The number of dimensions is equal to the length of the mean vector
58 * and to the number of rows and columns of the covariance matrix.
59 * It is frequently written as "p" in formulae.
60 * <p>
61 * <b>Note:</b> this constructor will implicitly create an instance of
62 * {@link Well19937c} as random generator to be used for sampling only (see
63 * {@link #sample()} and {@link #sample(int)}). In case no sampling is
64 * needed for the created distribution, it is advised to pass {@code null}
65 * as random generator via the appropriate constructors to avoid the
66 * additional initialisation overhead.
67 *
68 * @param means Vector of means.
69 * @param covariances Covariance matrix.
70 * @throws DimensionMismatchException if the arrays length are
71 * inconsistent.
72 * @throws SingularMatrixException if the eigenvalue decomposition cannot
73 * be performed on the provided covariance matrix.
74 * @throws NonPositiveDefiniteMatrixException if any of the eigenvalues is
75 * negative.
76 */
77 public MultivariateNormalDistribution(final double[] means,
78 final double[][] covariances)
79 throws SingularMatrixException,
80 DimensionMismatchException,
81 NonPositiveDefiniteMatrixException {
82 this(new Well19937c(), means, covariances);
83 }
84
85 /**
86 * Creates a multivariate normal distribution with the given mean vector and
87 * covariance matrix.
88 * <br/>
89 * The number of dimensions is equal to the length of the mean vector
90 * and to the number of rows and columns of the covariance matrix.
91 * It is frequently written as "p" in formulae.
92 *
93 * @param rng Random Number Generator.
94 * @param means Vector of means.
95 * @param covariances Covariance matrix.
96 * @throws DimensionMismatchException if the arrays length are
97 * inconsistent.
98 * @throws SingularMatrixException if the eigenvalue decomposition cannot
99 * be performed on the provided covariance matrix.
100 * @throws NonPositiveDefiniteMatrixException if any of the eigenvalues is
101 * negative.
102 */
103 public MultivariateNormalDistribution(RandomGenerator rng,
104 final double[] means,
105 final double[][] covariances)
106 throws SingularMatrixException,
107 DimensionMismatchException,
108 NonPositiveDefiniteMatrixException {
109 super(rng, means.length);
110
111 final int dim = means.length;
112
113 if (covariances.length != dim) {
114 throw new DimensionMismatchException(covariances.length, dim);
115 }
116
117 for (int i = 0; i < dim; i++) {
118 if (dim != covariances[i].length) {
119 throw new DimensionMismatchException(covariances[i].length, dim);
120 }
121 }
122
123 this.means = MathArrays.copyOf(means);
124
125 covarianceMatrix = new Array2DRowRealMatrix(covariances);
126
127 // Covariance matrix eigen decomposition.
128 final EigenDecomposition covMatDec = new EigenDecomposition(covarianceMatrix);
129
130 // Compute and store the inverse.
131 covarianceMatrixInverse = covMatDec.getSolver().getInverse();
132 // Compute and store the determinant.
133 covarianceMatrixDeterminant = covMatDec.getDeterminant();
134
135 // Eigenvalues of the covariance matrix.
136 final double[] covMatEigenvalues = covMatDec.getRealEigenvalues();
137
138 for (int i = 0; i < covMatEigenvalues.length; i++) {
139 if (covMatEigenvalues[i] < 0) {
140 throw new NonPositiveDefiniteMatrixException(covMatEigenvalues[i], i, 0);
141 }
142 }
143
144 // Matrix where each column is an eigenvector of the covariance matrix.
145 final Array2DRowRealMatrix covMatEigenvectors = new Array2DRowRealMatrix(dim, dim);
146 for (int v = 0; v < dim; v++) {
147 final double[] evec = covMatDec.getEigenvector(v).toArray();
148 covMatEigenvectors.setColumn(v, evec);
149 }
150
151 final RealMatrix tmpMatrix = covMatEigenvectors.transpose();
152
153 // Scale each eigenvector by the square root of its eigenvalue.
154 for (int row = 0; row < dim; row++) {
155 final double factor = FastMath.sqrt(covMatEigenvalues[row]);
156 for (int col = 0; col < dim; col++) {
157 tmpMatrix.multiplyEntry(row, col, factor);
158 }
159 }
160
161 samplingMatrix = covMatEigenvectors.multiply(tmpMatrix);
162 }
163
164 /**
165 * Gets the mean vector.
166 *
167 * @return the mean vector.
168 */
169 public double[] getMeans() {
170 return MathArrays.copyOf(means);
171 }
172
173 /**
174 * Gets the covariance matrix.
175 *
176 * @return the covariance matrix.
177 */
178 public RealMatrix getCovariances() {
179 return covarianceMatrix.copy();
180 }
181
182 /** {@inheritDoc} */
183 public double density(final double[] vals) throws DimensionMismatchException {
184 final int dim = getDimension();
185 if (vals.length != dim) {
186 throw new DimensionMismatchException(vals.length, dim);
187 }
188
189 return FastMath.pow(2 * FastMath.PI, -0.5 * dim) *
190 FastMath.pow(covarianceMatrixDeterminant, -0.5) *
191 getExponentTerm(vals);
192 }
193
194 /**
195 * Gets the square root of each element on the diagonal of the covariance
196 * matrix.
197 *
198 * @return the standard deviations.
199 */
200 public double[] getStandardDeviations() {
201 final int dim = getDimension();
202 final double[] std = new double[dim];
203 final double[][] s = covarianceMatrix.getData();
204 for (int i = 0; i < dim; i++) {
205 std[i] = FastMath.sqrt(s[i][i]);
206 }
207 return std;
208 }
209
210 /** {@inheritDoc} */
211 @Override
212 public double[] sample() {
213 final int dim = getDimension();
214 final double[] normalVals = new double[dim];
215
216 for (int i = 0; i < dim; i++) {
217 normalVals[i] = random.nextGaussian();
218 }
219
220 final double[] vals = samplingMatrix.operate(normalVals);
221
222 for (int i = 0; i < dim; i++) {
223 vals[i] += means[i];
224 }
225
226 return vals;
227 }
228
229 /**
230 * Computes the term used in the exponent (see definition of the distribution).
231 *
232 * @param values Values at which to compute density.
233 * @return the multiplication factor of density calculations.
234 */
235 private double getExponentTerm(final double[] values) {
236 final double[] centered = new double[values.length];
237 for (int i = 0; i < centered.length; i++) {
238 centered[i] = values[i] - getMeans()[i];
239 }
240 final double[] preMultiplied = covarianceMatrixInverse.preMultiply(centered);
241 double sum = 0;
242 for (int i = 0; i < preMultiplied.length; i++) {
243 sum += preMultiplied[i] * centered[i];
244 }
245 return FastMath.exp(-0.5 * sum);
246 }
247}
Note: See TracBrowser for help on using the repository browser.