/*
* Copyright 1999-2002 Carnegie Mellon University.
* Portions Copyright 2002 Sun Microsystems, Inc.
* Portions Copyright 2002 Mitsubishi Electric Research Laboratories.
* All Rights Reserved. Use is subject to license terms.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*
*/
package edu.cmu.sphinx.linguist.acoustic.tiedstate;
import edu.cmu.sphinx.frontend.Data;
import edu.cmu.sphinx.frontend.DoubleData;
import edu.cmu.sphinx.frontend.FloatData;
import edu.cmu.sphinx.util.LogMath;
/**
* Represents a concrete implementation of a simple {@link Senone senone}. A simple senone is a set of probability
* density functions implemented as a Gaussian mixture.
* <p>
* All scores and weights are maintained in LogMath log base.
*/
@SuppressWarnings("serial")
public class GaussianMixture extends ScoreCachingSenone {
// these data element in a senone may be shared with other senones
// and therefore should not be written to.
protected GaussianWeights mixtureWeights;
private MixtureComponent[] mixtureComponents;
protected int id;
protected LogMath logMath;
/**
* Creates a new senone from the given components.
*
* @param mixtureWeights the mixture weights for this senone in LogMath log base
* @param mixtureComponents the mixture components for this senone
* @param id id of the mixture
*/
public GaussianMixture(GaussianWeights mixtureWeights,
MixtureComponent[] mixtureComponents, int id) {
logMath = LogMath.getLogMath();
this.mixtureComponents = mixtureComponents;
this.mixtureWeights = mixtureWeights;
this.id = id;
}
/**
* Dumps this senone.
*
* @param msg annotation message
*/
public void dump(String msg) {
System.out.println(msg + " GaussianMixture: ID " + getID());
}
/**
* Determines if two objects are equal
*
* @param o the object to compare to this.
* @return true if the objects are equal
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof Senone)) {
return false;
}
Senone other = (Senone) o;
return this.getID() == other.getID();
}
/**
* Returns the hashcode for this object
*
* @return the hashcode
*/
@Override
public int hashCode() {
long id = getID();
int high = (int) ((id >> 32));
int low = (int) (id);
return high + low;
}
public long getID() {
return id;
}
/**
* Retrieves a string form of this object
*
* @return the string representation of this object
*/
@Override
public String toString() {
return "senone id: " + getID();
}
@Override
public float calculateScore(Data feature) {
if (feature instanceof DoubleData)
System.err.println("DoubleData conversion required on mixture level!");
float[] featureVector = FloatData.toFloatData(feature).getValues();
float logTotal = LogMath.LOG_ZERO;
for (int i = 0; i < mixtureComponents.length; i++) {
// In linear form, this would be:
//
// Total += Mixture[i].score * MixtureWeight[i]
logTotal = logMath.addAsLinear(logTotal,
mixtureComponents[i].getScore(featureVector) + mixtureWeights.get(id, 0, i));
}
return logTotal;
}
/**
* Calculates the scores for each component in the senone.
*
* @param feature the feature to score
* @return the LogMath log scores for the feature, one for each component
*/
public float[] calculateComponentScore(Data feature) {
if (feature instanceof DoubleData)
System.err.println("DoubleData conversion required on mixture level!");
float[] featureVector = FloatData.toFloatData(feature).getValues();
float[] logComponentScore = new float[mixtureComponents.length];
for (int i = 0; i < mixtureComponents.length; i++) {
// In linear form, this would be:
//
// Total += Mixture[i].score * MixtureWeight[i]
logComponentScore[i] = mixtureComponents[i].getScore(featureVector) + mixtureWeights.get(id, 0, i);
}
return logComponentScore;
}
public MixtureComponent[] getMixtureComponents() {
return mixtureComponents;
}
/** @return the dimension of the modeled feature space */
public int dimension() {
return mixtureComponents[0].getMean().length;
}
/** @return the number of component densities of this <code>GaussianMixture</code>. */
public int numComponents() {
return mixtureComponents.length;
}
public float[] getLogMixtureWeights(){
float[] logWeights = new float[getMixtureComponents().length];
for (int i = 0; i < logWeights.length; i++)
logWeights[i] = mixtureWeights.get(id, 0, i);
return logWeights;
}
/** @return the (linearly scaled) mixture weights of the component densities */
public float[] getComponentWeights() {
float[] mixWeights = new float[getMixtureComponents().length];
for (int i = 0; i < mixWeights.length; i++)
mixWeights[i] = (float) logMath.logToLinear(mixtureWeights.get(id, 0, i));
return mixWeights;
}
/**
* @param index of the component
* @return the (log-scaled) mixture weight of the component density
* <code>index</code> */
public float getLogComponentWeight(int index) {
return mixtureWeights.get(id, 0, index);
}
}