我无法创建一个二维数组并用值填充它,然后读取数组并获得完全不同的值。奇怪的是我有两个维护两个数组,其中一个是正确存储值,另一个不是。我很确定我也没有覆盖元素。我假设我犯了一些愚蠢的错误,这对于不熟悉 C 的人来说是显而易见的。
请注意我正在实现维特比算法,但是我理解的一般算法并且有一个有效的 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], ... ]
当我为一小段数据运行代码时,比如 < 12 个观察值,我没有这样的问题。当我为更长的数据运行它时,我的大多数最佳路径表都没有正确填充——看起来模式是这样的:
observation#
1) correct
2-3) garbage
4) correct
4-5) garbage
and so on
代码
请参阅此要点。它不依赖于 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);
}
编辑2:
在代码的早期版本中,我正在执行更标准的二维数组初始化(在非连续块中)和相应的数组访问。这给了我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,固定代码: 可以在这里找到固定代码。我还为我的用例调整了发射和转换概率。