/*
* 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.trainer;
import edu.cmu.sphinx.util.LogMath;
/** Used to accumulate data for updating of models. */
class Buffer {
private double[] numerator;
private double denominator;
private boolean wasUsed;
// Maybe isLog should be used otherwise: one single, say,
// accumulate(), which would be directed according to isLog. But
// then again having accumulate() and logAccumulate() makes it
// clearer if we're dealing with log scale or not...
private boolean isLog;
private int id;
/**
* Creates a new buffer. If the values will be in log, the buffer is initialized to all
* <code>LogMath.LOG_ZERO</code>.
*
* @param size the number of elements in this buffer
* @param isLog if true, the values in the buffer will be in log
*/
Buffer(int size, boolean isLog, int id) {
this.id = id;
this.isLog = isLog;
wasUsed = false;
numerator = new double[size];
if (isLog) {
denominator = LogMath.LOG_ZERO;
for (int i = 0; i < size; i++) {
numerator[i] = LogMath.LOG_ZERO;
}
}
}
/**
* Accumulates data to this buffer. Data are accumulated to a given numerator buffer and to the denominator buffer.
*
* @param data the data to be added
* @param entry the numerator entry to be accumulated to
*/
void accumulate(float data, int entry) {
// Not needed anymore??
assert false;
assert numerator != null;
assert !isLog;
numerator[entry] += data;
denominator += data;
wasUsed = true;
}
/**
* Accumulates data to this buffer. Data are accumulated to a given numerator buffer and to the denominator buffer.
*
* @param data the data to be added
* @param entry the numerator entry to be accumulated to
* @param logMath the logMath to use
*/
void logAccumulate(float data, int entry, LogMath logMath) {
assert numerator != null;
assert isLog;
numerator[entry] = logMath.addAsLinear((float) numerator[entry], data);
denominator = logMath.addAsLinear((float) denominator, data);
wasUsed = true;
}
/**
* Accumulates data to this buffer. Data are accumulated to a given numerator buffer and to the denominator buffer.
*
* @param numeratorData the data to be added to the numerator
* @param denominatorData the data to be added to the denominator
*/
void accumulate(double[] numeratorData, double denominatorData) {
assert numerator != null;
assert numeratorData != null;
assert numerator.length == numeratorData.length;
assert !isLog;
for (int i = 0; i < numerator.length; i++) {
numerator[i] += numeratorData[i];
}
denominator += denominatorData;
wasUsed = true;
}
/**
* Accumulates data to this buffer. Data are accumulated to a given numerator buffer and to the denominator buffer.
*
* @param logNumeratorData the data to be added to the numerator
* @param logDenominatorData the data to be added to the denominator
* @param logMath the LogMath instance to be used
*/
void logAccumulate(float[] logNumeratorData, float logDenominatorData,
LogMath logMath) {
assert numerator != null;
assert logNumeratorData != null;
assert numerator.length == logNumeratorData.length;
assert isLog;
for (int i = 0; i < numerator.length; i++) {
numerator[i] =
logMath.addAsLinear((float) numerator[i], logNumeratorData[i]);
}
denominator = logMath.addAsLinear((float) denominator, logDenominatorData);
wasUsed = true;
}
/**
* Normalize the buffer. This method divides the numerator by the denominator, storing the result in the numerator,
* and setting denominator to 1.
*/
void normalize() {
assert !isLog;
if (denominator == 0) {
System.out.println("Empty denominator: " + id);
// dump();
// assert false;
wasUsed = false;
return;
}
double invDenominator = (1.0 / denominator);
for (int i = 0; i < numerator.length; i++) {
numerator[i] *= invDenominator;
}
denominator = 1.0;
}
/**
* Normalize the buffer in log scale. This method divides the numerator by the denominator, storing the result in
* the numerator, and setting denominator to log(1) = 0.
*/
void logNormalize() {
assert isLog;
for (int i = 0; i < numerator.length; i++) {
numerator[i] -= denominator;
}
denominator = 0.0f;
}
/**
* Normalize the non-zero elements in a buffer in log scale. This method divides the numerator by the denominator,
* storing the result in the numerator, and setting denominator to log(1) = 0. A mask is used to tell whether a
* component should be normalized (non-zero) or not (zero).
*
* @param mask a vector containing zero/non-zero values.
*/
void logNormalizeNonZero(float[] mask) {
assert isLog;
assert mask.length == numerator.length;
for (int i = 0; i < numerator.length; i++) {
if (mask[i] != LogMath.LOG_ZERO) {
numerator[i] -= denominator;
}
}
denominator = 0.0;
}
/** Normalize the buffer. The normalization is done so that the summation of elements in the buffer is 1. */
void normalizeToSum() {
assert !isLog;
float den = 0.0f;
for (double val : numerator) {
den += val;
}
float invDenominator = (float) (1.0 / den);
for (int i = 0; i < numerator.length; i++) {
numerator[i] *= invDenominator;
}
denominator = 1.0;
}
/**
* Normalize the buffer in log scale. The normalization is done so that the summation of elements in the buffer is
* log(1) = 0. In this, we assume that if an element has a value of zero, it won't be updated.
*
* @param logMath the logMath to use
*/
void logNormalizeToSum(LogMath logMath) {
assert isLog;
float logZero = LogMath.LOG_ZERO;
float den = logZero;
for (double val : numerator) {
if (val != logZero) {
den = logMath.addAsLinear(den, (float)val);
}
}
for (int i = 0; i < numerator.length; i++) {
if (numerator[i] != logZero) {
numerator[i] -= den;
}
}
denominator = 0.0;
}
/**
* Floor the buffer.
*
* @param floor the floor for this buffer
* @return if true, the buffer was modified
*/
protected boolean floor(float floor) {
assert !isLog;
boolean wasModified = false;
for (int i = 0; i < numerator.length; i++) {
if (numerator[i] < floor) {
wasModified = true;
numerator[i] = floor;
}
}
return wasModified;
}
/**
* Floor the buffer in log scale.
*
* @param logFloor the floor for this buffer, in log scale
* @return if true, the buffer was modified
*/
protected boolean logFloor(float logFloor) {
assert isLog;
boolean wasModified = false;
for (int i = 0; i < numerator.length; i++) {
if (numerator[i] < logFloor) {
wasModified = true;
numerator[i] = logFloor;
}
}
return wasModified;
}
/**
* Retrieves a value from this buffer. Make sure you normalize the buffer first.
*
* @param entry the index into the buffer
* @return the value
*/
protected float getValue(int entry) {
return (float) numerator[entry];
}
/**
* Set the entry in this buffer to a value.
*
* @param entry the index into the buffer
* @param value the value
*/
protected void setValue(int entry, float value) {
numerator[entry] = value;
}
/**
* Retrieves a vector from this buffer. Make sure you normalize the buffer first.
*
* @return the value
*/
protected float[] getValues() {
float[] returnVector = new float[numerator.length];
for (int i = 0; i < numerator.length; i++) {
returnVector[i] = (float) numerator[i];
}
return returnVector;
}
/**
* Returns whether the buffer was used.
*
* @return if true, the buffer was used
*/
protected boolean wasUsed() {
return wasUsed;
}
/** Dump info about this buffer. */
public void dump() {
System.out.println("Denominator= " + denominator);
System.out.println("Numerators= ");
for (int i = 0; i < numerator.length; i++) {
System.out.println("[" + i + "]= " + numerator[i]);
}
}
}