public override void DoWork() //based on https://en.wikipedia.org/wiki/Viterbi_algorithm#Pseudocode
        {
            base.DoWork();

            delta  = new Dictionary <TState, StateWithProbability[]>();
            Output = new TState[T];

            foreach (var iState in StateSpace)
            {
                delta[iState]    = new StateWithProbability[T];
                delta[iState][0] = new StateWithProbability(iState, Math.Log(InitialProbabilitiesOfStates[iState]));
            }

            for (var t = 1; t < T; t++)
            {
                foreach (var iState in StateSpace)
                {
                    delta[iState][t] = max(t, iState);
                }
            }

            Output[T - 1] = delta.Aggregate((a, b) => a.Value[T - 1].Probability > b.Value[T - 1].Probability ? a : b).Key;

            for (var i = T - 1; i > 0; i--)
            {
                Output[i - 1] = delta[Output[i]][i].State;
            }
        }
        private StateWithProbability max(int t, TState iState)
        {
            var max = new StateWithProbability(default(TState), double.MinValue);

            foreach (var jState in StateSpace)
            {
                var value = delta[jState][t - 1].Probability + Math.Log(TransitionMatrix[jState, iState]) +
                            Math.Log(EmissionMatrix[iState, SequenceOfObservations[t]]);
                if (value <= max.Probability)
                {
                    continue;
                }
                max = new StateWithProbability(jState, value);
            }
            return(max);
        }