public static function viterbi($sentence, $options = array())
{
$defaults = array('mode' => 'default');
$options = array_merge($defaults, $options);
$obs = $sentence;
$states = array('B', 'M', 'E', 'S');
$V = array();
$V[0] = array();
$path = array();
foreach ($states as $key => $state) {
$y = $state;
$c = mb_substr($obs, 0, 1, 'UTF-8');
$prob_emit = 0.0;
if (isset(self::$prob_emit[$y][$c])) {
$prob_emit = self::$prob_emit[$y][$c];
} else {
$prob_emit = MIN_FLOAT;
}
$V[0][$y] = self::$prob_start[$y] + $prob_emit;
$path[$y] = $y;
}
for ($t = 1; $t < mb_strlen($obs, 'UTF-8'); $t++) {
$c = mb_substr($obs, $t, 1, 'UTF-8');
$V[$t] = array();
$newpath = array();
foreach ($states as $key => $state) {
$y = $state;
$temp_prob_array = array();
foreach ($states as $key => $state0) {
$y0 = $state0;
$prob_trans = 0.0;
if (isset(self::$prob_trans[$y0][$y])) {
$prob_trans = self::$prob_trans[$y0][$y];
} else {
$prob_trans = MIN_FLOAT;
}
$prob_emit = 0.0;
if (isset(self::$prob_emit[$y][$c])) {
$prob_emit = self::$prob_emit[$y][$c];
} else {
$prob_emit = MIN_FLOAT;
}
$temp_prob_array[$y0] = $V[$t - 1][$y0] + $prob_trans + $prob_emit;
}
arsort($temp_prob_array);
$max_prob = reset($temp_prob_array);
$max_key = key($temp_prob_array);
$V[$t][$y] = $max_prob;
if (is_array($path[$max_key])) {
$newpath[$y] = array();
foreach ($path[$max_key] as $key => $path_value) {
array_push($newpath[$y], $path_value);
}
array_push($newpath[$y], $y);
} else {
$newpath[$y] = array($path[$max_key], $y);
}
}
$path = $newpath;
}
$es_states = array('E', 'S');
$temp_prob_array = array();
$len = mb_strlen($obs, 'UTF-8');
foreach ($es_states as $key => $state) {
$y = $state;
$temp_prob_array[$y] = $V[$len - 1][$y];
}
arsort($temp_prob_array);
$prob = reset($temp_prob_array);
$state = key($temp_prob_array);
return array("prob" => $prob, "pos_list" => $path[$state]);
}