public double Run(int[][] observations, int[][] paths)
{
// Grab model information
int N = observations.Length;
int states = model.States;
int symbols = model.Symbols;
Array.Clear(initial, 0, initial.Length);
Array.Clear(transitions, 0, transitions.Length);
Array.Clear(emissions, 0, emissions.Length);
// 1. Count first state occurrences
for (int i = 0; i < paths.Length; i++)
initial[paths[i][0]]++;
// 2. Count all state transitions
foreach (int[] path in paths)
for (int j = 1; j < path.Length; j++)
transitions[path[j - 1], path[j]]++;
// 3. Count emissions for each state
for (int i = 0; i < observations.Length; i++)
for (int j = 0; j < observations[i].Length; j++)
emissions[paths[i][j], observations[i][j]]++;
// 4. Form log-probabilities, using the Laplace
// correction to avoid zero probabilities
if (useLaplaceRule)
{
// Use Laplace's rule of succession correction
// http://en.wikipedia.org/wiki/Rule_of_succession
for (int i = 0; i < initial.Length; i++)
{
initial[i]++;
for (int j = 0; j < states; j++)
transitions[i, j]++;
for (int k = 0; k < symbols; k++)
emissions[i, k]++;
}
}
// Form probabilities
int initialCount = initial.Sum();
int[] transitionCount = transitions.Sum(1);
int[] emissionCount = emissions.Sum(1);
if (initialCount == 0)
initialCount = 1;
for (int i = 0; i < transitionCount.Length; i++)
{
if (transitionCount[i] == 0)
transitionCount[i] = 1;
}
for (int i = 0; i < emissionCount.Length; i++)
{
if (emissionCount[i] == 0)
emissionCount[i] = 1;
}
for (int i = 0; i < initial.Length; i++)
model.LogInitial[i] = Math.Log(initial[i] / (double)initialCount);
for (int i = 0; i < transitionCount.Length; i++)
for (int j = 0; j < states; j++)
model.LogTransitions[i][j] = Math.Log(transitions[i, j] / (double)transitionCount[i]);
for (int i = 0; i < emissionCount.Length; i++)
for (int j = 0; j < symbols; j++)
model.LogEmissions[i][j] = Math.Log(emissions[i, j] / (double)emissionCount[i]);
Accord.Diagnostics.Debug.Assert(!model.LogInitial.HasNaN());
Accord.Diagnostics.Debug.Assert(!model.LogTransitions.HasNaN());
Accord.Diagnostics.Debug.Assert(!model.Emissions.HasNaN());
// 5. Compute log-likelihood
double logLikelihood = Double.NegativeInfinity;
for (int i = 0; i < observations.Length; i++)
logLikelihood = Special.LogSum(logLikelihood, model.Evaluate(observations[i]));
return logLikelihood;
}