Пиша C разширение, което ще се занимава с масиви numpy. Написах функция за четене и извеждане на масива numpy. Използвайки го, забелязах странно поведение, което се появява, когато използвам нарязване във входния масив.
Функцията 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 разширение, т.е. потребителите на моето разширение няма да се интересуват дали техният вход е „нарязан“ или не. Въпреки това се опитах да поставя дълбоко копие на aSliced
в моето разширение - което имаше същия грешен резултат като aSliced
.
Работя с python 3.4 64bit, numpy 1.9.1, Win8 64bit и Visual Studio 10 64bit C компилатор.
.flags
или.__array_interface__
. Булевото индексиране създава копие и в този случай то еF_CONTIGUOUS
. - person hpaulj   schedule 29.05.2015