public int[] Decode(Array observations, bool logarithm, out double probability)
{
if (observations == null)
throw new ArgumentNullException("observations");
if (observations.Length == 0)
{
probability = 0.0;
return new int[0];
}
if (!(observations is double[][] || observations is double[]))
throw new ArgumentException("Argument should be either of type " +
"double[] (for univariate observation) or double[][] (for " +
"multivariate observation).", "observations");
double[][] x = convert(observations);
// Viterbi-forward algorithm.
int T = x.Length;
int states = States;
int minState;
double minWeight;
double weight;
double[] pi = Probabilities;
double[,] A = Transitions;
var s = new int[states,T];
var a = new double[states,T];
// Base
for (int i = 0; i < states; i++)
a[i, 0] = -System.Math.Log(pi[i]) - System.Math.Log(B[i].ProbabilityFunction(x[0]));
// Induction
for (int t = 1; t < T; t++)
{
double[] observation = x[t];
for (int j = 0; j < states; j++)
{
minState = 0;
minWeight = a[0, t - 1] - System.Math.Log(A[0, j]);
for (int i = 1; i < states; i++)
{
weight = a[i, t - 1] - System.Math.Log(A[i, j]);
if (weight < minWeight)
{
minState = i;
minWeight = weight;
}
}
a[j, t] = minWeight - System.Math.Log(B[j].ProbabilityFunction(observation));
s[j, t] = minState;
}
}
// Find minimum value for time T-1
minState = 0;
minWeight = a[0, T - 1];
for (int i = 1; i < states; i++)
{
if (a[i, T - 1] < minWeight)
{
minState = i;
minWeight = a[i, T - 1];
}
}
// Trackback
var path = new int[T];
path[T - 1] = minState;
for (int t = T - 2; t >= 0; t--)
path[t] = s[path[t + 1], t + 1];
// Returns the sequence probability as an out parameter
probability = logarithm ? -minWeight : System.Math.Exp(-minWeight);
// Returns the most likely (Viterbi path) for the given sequence
return path;
}