public int[] Decode(double[][] observations, out double logLikelihood)
{
if (observations == null)
throw new ArgumentNullException("observations");
if (observations.Length == 0)
{
logLikelihood = Double.NegativeInfinity;
return new int[0];
}
// Viterbi-forward algorithm.
int T = observations.Length;
int states = States;
int maxState;
double maxWeight;
double weight;
int[,] s = new int[states, T];
double[,] lnFwd = new double[states, T];
double[][] output = new double[states][];
// Base
output[0] = Function(-1, observations[0]);
for (int i = 0; i < states; i++)
lnFwd[i, 0] = output[0][i];
// Induction
for (int t = 1; t < T; t++)
{
double[] observation = observations[t];
for (int i = 0; i < States; i++)
output[i] = Function(i, observation);
for (int j = 0; j < states; j++)
{
maxState = 0;
maxWeight = lnFwd[0, t - 1] + output[0][j];
for (int i = 1; i < states; i++)
{
weight = lnFwd[i, t - 1] + output[i][j];
if (weight > maxWeight)
{
maxState = i;
maxWeight = weight;
}
}
lnFwd[j, t] = maxWeight;
s[j, t] = maxState;
}
}
// Find maximum value for time T-1
maxState = 0;
maxWeight = lnFwd[0, T - 1];
for (int i = 1; i < states; i++)
{
if (lnFwd[i, T - 1] > maxWeight)
{
maxState = i;
maxWeight = lnFwd[i, T - 1];
}
}
// Trackback
int[] path = new int[T];
path[T - 1] = maxState;
for (int t = T - 2; t >= 0; t--)
path[t] = s[path[t + 1], t + 1];
// Returns the sequence probability as an out parameter
logLikelihood = maxWeight;
// Returns the most likely (Viterbi path) for the given sequence
return path;
}