我正在写一个C扩展,它将处理numpy数组。我写了一个函数来读取和输出numpy数组。使用它,我注意到当我在输入数组中使用切片时出现的奇怪行为。
读取(boolan)数组的C函数:
char **pymatrix_to_CarrayptrsChar(PyArrayObject *arrayin) {
char **result, *array;
int i, n, m, j;
n = arrayin->dimensions[0];
m = arrayin->dimensions[1];
result = ptrvectorChar(n, m);
array = (char *) arrayin->data; /* pointer to arrayin data as int */
for (i = 0; i < n; i++) {
result[i] = &array[i * m];
}
printArrChar(result, n, m);
return result;
}
ptrvectorChar
是内存分配的函数:
char **ptrvectorChar(long dim1) {
char **v;
if (!(v = malloc(dim1 * sizeof(char*)))) {
PyErr_SetString(PyExc_MemoryError,
"In **ptrvectorChar. Allocation of memory for character array failed.");
exit(0);
}
return v;
}
打印完成:
void printArrChar(char **arr, int dim1, int dim2) {
int i, j;
for (i = 0; i < dim1; i++) {
for (j = 0; j < dim2; j++) {
printf("%i ", arr[i][j]);
}
printf("\n");
}
}
我的用于重现错误的python脚本是:
import numpy as np
import MyExtension
np.random.seed(1)
x = np.array((1,1,1,1,1,1)).astype(bool)
a = np.round(np.random.rand(trialNr, lakeNr)).astype(bool)
aSlicing = a[:, x]
print("a:")
print(a + 0)
print("aSlicing:")
print(aSlicing + 0)
print("C output for a:")
MyExtension.MyFunction(a)
print("C output for aSlicing:")
MyExtension.MyFunction(aSlicing)
输出是:
a:
[[0 1 0 0 0 0]
[0 0 0 1 0 1]
[0 1 0 1 0 1]
[0 0 1 1 0 1]
[1 1 0 0 0 1]
[0 0 1 1 1 0]
[1 1 0 1 1 1]
[0 1 0 0 1 0]
[0 0 0 1 0 0]
[0 0 1 0 1 1]]
aSlicing:
[[0 1 0 0 0 0]
[0 0 0 1 0 1]
[0 1 0 1 0 1]
[0 0 1 1 0 1]
[1 1 0 0 0 1]
[0 0 1 1 1 0]
[1 1 0 1 1 1]
[0 1 0 0 1 0]
[0 0 0 1 0 0]
[0 0 1 0 1 1]]
C output for a:
0 1 0 0 0 0
0 0 0 1 0 1
0 1 0 1 0 1
0 0 1 1 0 1
1 1 0 0 0 1
0 0 1 1 1 0
1 1 0 1 1 1
0 1 0 0 1 0
0 0 0 1 0 0
0 0 1 0 1 1
C output for aSlicing:
0 0 0 0 1 0
1 0 0 0 1 0
1 0 1 0 1 1
0 0 0 0 0 1
0 1 0 0 0 1
0 1 1 1 0 1
1 0 1 0 0 0
0 0 0 1 1 1
0 1 0 1 1 1
1 0 1 0 0 1
可以很容易地看出,a
和aSlicing
是python的相同数组。但是,读取数据的C函数将数据视为转置的类型。 C认为aSliced好像是
a.T.reshape((10,6))
有谁知道为什么会出现此错误以及如何正确规避错误?当然,在C代码中进行转置很容易。但是,我希望我的程序能够处理这两种类型的数组。
我希望在我的C扩展中有一个解决方案,即我的扩展名的用户不必关心他们的输入是否是&#34;切片&#34;或不。不过,我尝试将aSliced
的深层副本放入我的扩展程序中 - 这与aSliced
的错误结果相同。
我正在使用python 3.4 64bit,numpy 1.9.1,Win8 64bit和Visual Studio 10 64bit C编译器。
答案 0 :(得分:0)
正如hpaulj指出的那样,可以使用标志F_CONTIGUOUS
找出内存结构。我花了很多时间试图从C中找到一种方法来读取这个标志。据我所知,可以通过评估trials_array->flags % 2
的值来完成。但是,我没有找到任何有关此问题的明确表述的参考文献。
trials_array->flags
是整数。 numpy标志常量NPY_C_CONTIGUOUS
,NPY_F_CONTIGUOUS
等是两个幂的整数。如果trials_array->flags
的二进制表示中的相应位置为1,则设置该标志似乎是真的。
即使知道了内存结构,它也不像我想的那样读取数组。我找到了一种更简单的方式将numpy数组转换为C数组:使用
char *myArray;
PyArrayObject *myArray_Numpy;
PyArray_AsCArray(&myArray_Numpy, (void *) &myArray, myArray_Numpy->dimensions, 2, PyArray_DescrFromType(NPY_BOOL));
//Do something with the array
PyArray_Free(myArray_Numpy, myArray);
我找到了使用这些函数here的示例。