/**
* Copyright 2007 DFKI GmbH.
* All Rights Reserved. Use is subject to license terms.
*
* This file is part of MARY TTS.
*
* MARY TTS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package marytts.machinelearning;
import java.io.IOException;
import marytts.util.io.MaryRandomAccessFile;
import marytts.util.math.MathUtils;
/**
*
* Implements a single Gaussian component with a mean vector and a covariance matrix It also computes terms for pdf computation
* out of this Gaussian component once the mean and covariance is specified
*
* @author Oytun Türk
*/
public class GaussianComponent {
public double[] meanVector;
public double[][] covMatrix;
// These are used in pdf computation
private double[][] invCovMatrix;
private double detCovMatrix;
private double constantTerm;
private double constantTermLog;
//
public GaussianComponent() {
this(0, true);
}
public GaussianComponent(int featureDimensionIn, boolean isDiagonal) {
init(featureDimensionIn, isDiagonal);
}
public GaussianComponent(GaussianComponent existing) {
init(existing.meanVector, existing.covMatrix);
}
public GaussianComponent(Cluster c) {
init(c.meanVector, c.covMatrix);
}
public void init(int featureDimensionIn, boolean isDiagonal) {
if (featureDimensionIn > 0) {
meanVector = new double[featureDimensionIn];
if (isDiagonal)
covMatrix = new double[1][featureDimensionIn];
else
covMatrix = new double[featureDimensionIn][featureDimensionIn];
} else {
meanVector = null;
covMatrix = null;
}
}
public void init(double[] meanVectorIn, double[][] covMatrixIn) {
setMeanVector(meanVectorIn);
setCovMatrix(covMatrixIn);
for (int i = 0; i < covMatrix.length; i++)
assert meanVector.length == covMatrix[i].length;
}
public void setMeanVector(double[] meanVectorIn) {
setMeanVector(meanVectorIn, 0, meanVectorIn.length);
}
public void setMeanVector(double[] bigVector, int startIndex, int meanLength) {
if (bigVector != null && meanLength > 0) {
if (startIndex + meanLength > bigVector.length)
meanLength = bigVector.length - startIndex;
if (meanVector == null || meanLength != meanVector.length)
meanVector = new double[meanLength];
for (int i = 0; i < meanLength; i++)
meanVector[i] = bigVector[startIndex + i];
} else
meanVector = null;
}
public void setCovMatrix(double[][] covMatrixIn) {
if (covMatrixIn.length == 1)
setCovMatrix(covMatrixIn, 0, 0, covMatrixIn[0].length);
else
setCovMatrix(covMatrixIn, 0, 0, covMatrixIn.length);
}
public void setCovMatrix(double[][] bigCovMatrix, int rowStartIndex, int colStartIndex, int covLength) {
if (bigCovMatrix != null && covLength > 0) {
if (bigCovMatrix.length == 1) // Diagonal
{
int startIndex = Math.max(rowStartIndex, colStartIndex);
if (startIndex + covLength > bigCovMatrix[0].length)
covLength = bigCovMatrix[0].length - startIndex;
if (covMatrix == null || covMatrix.length > 1 || covMatrix[0].length != covLength)
covMatrix = new double[1][covLength];
System.arraycopy(bigCovMatrix[0], startIndex, covMatrix[0], 0, covLength);
} else // Full
{
int i, j;
for (i = 0; i < bigCovMatrix.length; i++) {
if (colStartIndex + covLength > bigCovMatrix[i].length)
covLength = bigCovMatrix[i].length - colStartIndex;
}
if (rowStartIndex + covLength > bigCovMatrix.length)
covLength = bigCovMatrix.length - rowStartIndex;
if (covMatrix == null)
covMatrix = new double[covLength][];
for (i = rowStartIndex; i < rowStartIndex + covLength; i++) {
if (covMatrix[i - rowStartIndex] == null || covMatrix[i - rowStartIndex].length != covLength)
covMatrix[i - rowStartIndex] = new double[covLength];
for (j = colStartIndex; j < colStartIndex + covLength; j++)
covMatrix[i - rowStartIndex][j - colStartIndex] = bigCovMatrix[i][j];
}
}
} else
covMatrix = null;
setDerivedValues();
}
// Computes the inverse covariance, determinant, constant term to be used in pdf evalutaion
public void setDerivedValues() {
if (covMatrix != null) {
invCovMatrix = MathUtils.inverse(covMatrix);
detCovMatrix = MathUtils.determinant(covMatrix);
constantTerm = MathUtils.getGaussianPdfValueConstantTerm(covMatrix[0].length, detCovMatrix);
constantTermLog = MathUtils.getGaussianPdfValueConstantTermLog(covMatrix[0].length, detCovMatrix);
} else {
invCovMatrix = null;
detCovMatrix = 0.0;
constantTerm = 0.0;
constantTermLog = 0.0;
}
}
public boolean isDiagonalCovariance() {
if (meanVector != null && covMatrix != null) {
if (covMatrix.length == 1 && meanVector.length > 1 && covMatrix[0].length == meanVector.length)
return true;
}
return false;
}
public double[] getCovMatrixDiagonal() {
if (covMatrix != null)
return covMatrix[0];
else
return null;
}
public double[][] getInvCovMatrix() {
return invCovMatrix;
}
public double getDetCovMatrix() {
return detCovMatrix;
}
public double getConstantTerm() {
return constantTerm;
}
public double getConstantTermLog() {
return constantTermLog;
}
public void write(MaryRandomAccessFile stream) throws IOException {
boolean isDiagonal = isDiagonalCovariance();
stream.writeBooleanEndian(isDiagonal);
if (meanVector != null) {
stream.writeIntEndian(meanVector.length);
stream.writeDoubleEndian(meanVector);
} else
stream.writeIntEndian(0);
int i;
if (covMatrix != null)
stream.writeIntEndian(covMatrix.length);
else
stream.writeIntEndian(0);
if (covMatrix != null) {
for (i = 0; i < covMatrix.length; i++) {
if (covMatrix[i] != null) {
stream.writeIntEndian(covMatrix[i].length);
stream.writeDoubleEndian(covMatrix[i]);
} else
stream.writeIntEndian(0);
}
}
if (invCovMatrix != null)
stream.writeIntEndian(invCovMatrix.length);
else
stream.writeIntEndian(0);
if (invCovMatrix != null) {
for (i = 0; i < invCovMatrix.length; i++) {
if (invCovMatrix[i] != null) {
stream.writeIntEndian(invCovMatrix[i].length);
stream.writeDoubleEndian(invCovMatrix[i]);
} else
stream.writeIntEndian(0);
}
}
stream.writeDoubleEndian(detCovMatrix);
stream.writeDoubleEndian(constantTerm);
stream.writeDoubleEndian(constantTermLog);
}
public void read(MaryRandomAccessFile stream) throws IOException {
boolean isDiagonal = stream.readBooleanEndian(); // This is for compatibility with C version
int tmpLen, tmpLen2;
tmpLen = stream.readIntEndian();
if (tmpLen > 0)
meanVector = stream.readDoubleEndian(tmpLen);
else
meanVector = null;
int i;
tmpLen = stream.readIntEndian();
if (tmpLen > 0) {
covMatrix = new double[tmpLen][];
for (i = 0; i < tmpLen; i++) {
tmpLen2 = stream.readIntEndian();
if (tmpLen2 > 0)
covMatrix[i] = stream.readDoubleEndian(tmpLen2);
else
covMatrix[i] = null;
}
} else
covMatrix = null;
tmpLen = stream.readIntEndian();
if (tmpLen > 0) {
invCovMatrix = new double[tmpLen][];
for (i = 0; i < tmpLen; i++) {
tmpLen2 = stream.readIntEndian();
if (tmpLen2 > 0)
invCovMatrix[i] = stream.readDoubleEndian(tmpLen2);
else
invCovMatrix[i] = null;
}
} else
invCovMatrix = null;
detCovMatrix = stream.readDoubleEndian();
constantTerm = stream.readDoubleEndian();
constantTermLog = stream.readDoubleEndian();
}
public double probability(double[] x) {
double P;
if (covMatrix.length == 1) // Diagonal
P = MathUtils.getGaussianPdfValue(x, meanVector, covMatrix[0], getConstantTerm());
else
// Full-covariance
P = MathUtils.getGaussianPdfValue(x, meanVector, getDetCovMatrix(), getInvCovMatrix());
return P;
}
}