/* * Encog(tm) Core v3.4 - Java Version * http://www.heatonresearch.com/encog/ * https://github.com/encog/encog-java-core * Copyright 2008-2016 Heaton Research, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * For more information on Heaton Research copyrights, licenses * and trademarks visit: * http://www.heatonresearch.com/copyright */ package org.encog.ml.hmm.distributions; import java.util.Arrays; import java.util.Random; import org.encog.mathutil.matrices.Matrix; import org.encog.mathutil.matrices.MatrixMath; import org.encog.mathutil.matrices.decomposition.CholeskyDecomposition; import org.encog.ml.data.MLDataPair; import org.encog.ml.data.MLDataSet; import org.encog.ml.data.basic.BasicMLData; import org.encog.ml.data.basic.BasicMLDataPair; import org.encog.util.EngineArray; /** * A continuous distribution represents an infinite range of choices between two * real numbers. A gaussian distribution is used to distribute the probability. * */ public class ContinousDistribution implements StateDistribution { /** * The serial id. */ private static final long serialVersionUID = 1L; /** * The dimensions. */ final private int dimension; /** * The means for each dimension. */ final private double[] mean; /** * The covariance matrix. */ final private Matrix covariance; /** * The covariance left side. */ private Matrix covarianceL = null; /** * The covariance inverse. */ private Matrix covarianceInv = null; /** * The covariance determinant. */ private double covarianceDet; /** * Random number generator. */ private final static Random randomGenerator = new Random(); /** * Used to perform a decomposition. */ private CholeskyDecomposition cd; /** * Construct a continuous distribution. * @param mean The mean. * @param covariance The covariance. */ public ContinousDistribution(final double[] mean, final double[][] covariance) { this.dimension = covariance.length; this.mean = EngineArray.arrayCopy(mean); this.covariance = new Matrix(covariance); update(covariance); } /** * Construct a continuous distribution with the specified number of dimensions. * @param dimension The dimensions. */ public ContinousDistribution(final int dimension) { if (dimension <= 0) { throw new IllegalArgumentException(); } this.dimension = dimension; this.mean = new double[dimension]; this.covariance = new Matrix(dimension, dimension); } /** * {@inheritDoc} */ @Override public ContinousDistribution clone() { try { return (ContinousDistribution) super.clone(); } catch (final CloneNotSupportedException e) { throw new AssertionError(e); } } /** * {@inheritDoc} */ @Override public void fit(final MLDataSet co) { final double[] weights = new double[co.size()]; Arrays.fill(weights, 1. / co.size()); fit(co, weights); } /** * {@inheritDoc} */ @Override public void fit(final MLDataSet co, final double[] weights) { if ((co.size() < 1) || (co.size() != weights.length)) { throw new IllegalArgumentException(); } // Compute mean final double[] mean = new double[this.dimension]; for (int r = 0; r < this.dimension; r++) { int i = 0; for (final MLDataPair o : co) { mean[r] += o.getInput().getData(r) * weights[i++]; } } // Compute covariance final double[][] covariance = new double[this.dimension][this.dimension]; int i = 0; for (final MLDataPair o : co) { final double[] obs = o.getInput().getData(); final double[] omm = new double[obs.length]; for (int j = 0; j < obs.length; j++) { omm[j] = obs[j] - mean[j]; } for (int r = 0; r < this.dimension; r++) { for (int c = 0; c < this.dimension; c++) { covariance[r][c] += omm[r] * omm[c] * weights[i]; } } i++; } update(covariance); } /** * {@inheritDoc} */ @Override public MLDataPair generate() { final double[] d = new double[this.dimension]; for (int i = 0; i < this.dimension; i++) { d[i] = ContinousDistribution.randomGenerator.nextGaussian(); } final double[] d2 = MatrixMath.multiply(this.covarianceL, d); return new BasicMLDataPair(new BasicMLData(EngineArray.add(d2, this.mean))); } /** * {@inheritDoc} */ @Override public double probability(final MLDataPair o) { final double[] v = o.getInputArray(); final Matrix vmm = Matrix.createColumnMatrix(EngineArray.subtract(v, this.mean)); final Matrix t = MatrixMath.multiply(this.covarianceInv, vmm); final double expArg = MatrixMath.multiply(MatrixMath.transpose(vmm), t) .get(0, 0) * -0.5; return Math.exp(expArg) / (Math.pow(2.0 * Math.PI, this.dimension / 2.0) * Math.pow( this.covarianceDet, 0.5)); } /** * Update the covariance. * @param covariance The new covariance. */ public void update(final double[][] covariance) { this.cd = new CholeskyDecomposition(new Matrix(covariance)); this.covarianceL = this.cd.getL(); this.covarianceInv = this.cd.inverseCholesky(); this.covarianceDet = this.cd.getDeterminant(); } /** * @return The mean for the dimensions of the gaussian curve. */ public double[] getMean() { return this.mean; } /** * @return The covariance matrix. */ public Matrix getCovariance() { return this.covariance; } }