int[] hiddenSequence, double pseudoCount) {
// make sure the pseudo count is not zero
pseudoCount = pseudoCount == 0 ? Double.MIN_VALUE : pseudoCount;
// initialize the parameters
DenseMatrix transitionMatrix = new DenseMatrix(nrOfHiddenStates, nrOfHiddenStates);
DenseMatrix emissionMatrix = new DenseMatrix(nrOfHiddenStates, nrOfOutputStates);
// assign a small initial probability that is larger than zero, so
// unseen states will not get a zero probability
transitionMatrix.assign(pseudoCount);
emissionMatrix.assign(pseudoCount);
// given no prior knowledge, we have to assume that all initial hidden
// states are equally likely
DenseVector initialProbabilities = new DenseVector(nrOfHiddenStates);
initialProbabilities.assign(1.0 / nrOfHiddenStates);
// now loop over the sequences to count the number of transitions
countTransitions(transitionMatrix, emissionMatrix, observedSequence,
hiddenSequence);
// make sure that probabilities are normalized
for (int i = 0; i < nrOfHiddenStates; i++) {
// compute sum of probabilities for current row of transition matrix
double sum = 0;
for (int j = 0; j < nrOfHiddenStates; j++) {
sum += transitionMatrix.getQuick(i, j);
}
// normalize current row of transition matrix
for (int j = 0; j < nrOfHiddenStates; j++) {
transitionMatrix.setQuick(i, j, transitionMatrix.getQuick(i, j) / sum);
}
// compute sum of probabilities for current row of emission matrix
sum = 0;
for (int j = 0; j < nrOfOutputStates; j++) {
sum += emissionMatrix.getQuick(i, j);
}
// normalize current row of emission matrix
for (int j = 0; j < nrOfOutputStates; j++) {
emissionMatrix.setQuick(i, j, emissionMatrix.getQuick(i, j) / sum);
}
}
// return a new model using the parameter estimations
return new HmmModel(transitionMatrix, emissionMatrix, initialProbabilities);