【发布时间】:2013-08-02 21:15:30
【问题描述】:
我无法创建二维数组并用值填充它,然后读取数组并获得完全不同的值。奇怪的是我有两个维护两个数组,其中一个是正确存储值,另一个不是。我很确定我也没有覆盖元素。我假设我犯了一些愚蠢的错误,这对于不熟悉 C 的人来说是显而易见的。
请注意我正在实现viterbi algorithm,但我理解的一般算法并且有一个有效的python实现,只是c中的数组让我很伤心。
我在做什么:
1) malloc 两个数组,它们被用作二维数组,但我分配了一个连续的内存块。我没有显式地初始化数组,因为我应该填写其中的每个条目,就像通过维特比算法的前进步骤一样。
double *viterbi_table = malloc(sizeof(double) * n_samples * n_states);
int *best_path_table = malloc(sizeof(int) * n_samples * n_states);
2) 对于维特比算法的前向部分,我遍历观察到的数据,并计算最可能的状态和每个状态的概率。
for (t = 1; t < n_samples; t++) // for each piece of observed data
{
for (i = 0; i < n_states; i++)
{
max_state_index = 0;
max_p = -DBL_MAX;
// calculate the max state and probability by looping through all the states
// yada yada...
// IMPORTANT PART: We set the array values here
viterbi_table[t * n_samples + i] = max_p;
best_path_table[t * n_samples + i] = max_state_index;
printf("\tbest_path_table[%d][%d] or [%d] = %d => %d\n",
i, t, t * n_samples + i, best_path_table[t * n_samples + i], max_state_index);
}
// IMPORTANT PART: print out rows of best path table to see if what we thought we inserted is in there
if (debug)
{
printf("best_path, [ ", t);
for (i = 0; i < n_states; i++)
{
printf("[%d], %d ", t * n_samples + i, best_path_table[t * n_samples + i]);
}
printf("]\n");
}
}
3) 我运行代码,而不是让我设置的数组元素与我认为我设置的元素匹配,而是得到看起来像未初始化元素的大负数或正数。是什么赋予了?我为这些块分配了一个值。这是显示问题的输出的选定部分。
t=36 => sample=X
best_path_table[0][36] or [1404] = 0 => 0
best_path_table[1][36] or [1405] = 0 => 0
best_path_table[2][36] or [1406] = 0 => 0
best_path_table[3][36] or [1407] = 0 => 0
...
best_path, [ [1404], 1399607453 [1405], -1070347604 [1406], 1399607453 [1407], 0 ... ]
通过对比,下面这个是正确的。
t=37 => sample=X
best_path_table[0][37] or [1443] = 3 => 3
best_path_table[1][37] or [1444] = 3 => 3
best_path_table[2][37] or [1445] = 3 => 3
...
best_path, [ [1443], 3 [1444], 3 [1445], ... ]
当我为一小段数据运行代码时,比如
observation#
1) correct
2-3) garbage
4) correct
4-5) garbage
and so on
代码
见this gist。它不依赖于 3rd 方库。
编辑:
维特比表的第一行在算法前向部分之前的一步中初始化。
for (i = 0; i < n_states; i++)
{
state_i = states[i];
sample_t = samples[0];
viterbi_table[i*n_samples]
= prior(state_i, 0, true) + emission(sample_t, state_i, true);
}
EDIT2:
在之前的代码版本中,我正在执行更标准的二维数组初始化(在非连续块中)和相应的数组访问。对于更大的输入数据,这给了我bus error,这完全有道理。
double **viterbi_table = malloc(sizeof * viterbi_table * n_states);
int **best_path_table = malloc(sizeof * best_path_table * n_states);
...
viterbi_table[j][t - 1] = ...
EDIT3,解决方案评论:
原来这是一个愚蠢的下标错误。维特比和最佳路径数组的大小为 n_samples * n_states,即 17 * 39 = 663。这排除了我的示例中的任何 1404 索引。
具体的问题是我的数组索引是一团糟,因为我错误地使用了 n_samples 而不是 n_states。对于给定的观测指数 t (30) 和给定的状态指数 i (14),计算如下:
// Original, wrong
t * n_samples + i = 30 * 39 + 14 = 1184
// New, correct
t * n_states + i = 30 * 17 + 14 = 524
变量t 已经编码了我们所处的样本数,所以我们只需要将它乘以状态数。
EDIT4,固定代码: 固定代码可以找到here。我还为我的用例调整了发射和转换概率。
【问题讨论】:
-
如果有的话,this 问题值得this one 投赞成票,因为它为研究解决方案所做的努力。 +1。
-
(t = 1; t < n_samples; t++)这可能是错误的,如果你有n_samples,循环应该从0开始。 -
@KarolyHorvath
t = 1是正确的(根据我对算法的理解)。 -
max_state_index始终为 0。 -
即使 t = 1 是正确的,数组中仍然存在垃圾值。他们需要被清除。