fix(stats): refuse a zero-probability sequence in Viterbi

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-27 15:41:19 +02:00
parent e507adeb64
commit 2f9358c512
3 changed files with 35 additions and 0 deletions
+26
View File
@@ -375,3 +375,29 @@ func TestHiddenMarkovFitSingleObservation(t *testing.T) {
}
}
}
func TestViterbiZeroProbabilitySequence(t *testing.T) {
// Symbol 2 is emitted by no state, so every path through the sequence
// has probability zero. Forward and Smooth refuse such a sequence, and
// Viterbi documents the same refusals: a meaningless path beside a
// −Inf log probability is not an answer.
model, err := NewHiddenMarkovModel(
[]float64{0.5, 0.5},
[]float64{0.5, 0.5, 0.5, 0.5},
[]float64{0.5, 0.5, 0, 0.5, 0.5, 0},
)
if err != nil {
t.Fatal(err)
}
if _, _, err := model.Viterbi([]int{0, 2, 1}); err == nil {
t.Fatal("a zero-probability sequence was accepted by Viterbi")
}
// The live symbols of the same model still decode.
path, lp, err := model.Viterbi([]int{0, 1})
if err != nil {
t.Fatal(err)
}
if path[0] != path[1] || lp >= 0 {
t.Fatalf("Viterbi([0, 1]) = (%v, %g), want a coherent path with a negative log probability", path, lp)
}
}