Python ctypes и np.array.ctypes.data_as неожиданное поведение при нарезкеPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Python ctypes и np.array.ctypes.data_as неожиданное поведение при нарезке

Сообщение Anonymous »

Используя ctypes Python и библиотеку numpy, я передаю данные в общую библиотеку и сталкиваюсь с очень странным поведением
Функция C:

Код: Выделить всё

#include 
typedef struct {
double *a;
double *b;
} s_gate;
void printdouble(s_gate*, int);

void printdouble(s_gate *gate, int n) {
for (int i =0; i < n; i++) {
printf("gate->a[%d] = %f\n", i, gate->a[i]);
}
for (int i =0; i < n; i++) {
printf("gate->b[%d] = %f\n", i, gate->b[i]);
}
}
Код Python:

Код: Выделить всё

import ctypes
import numpy as np
class s_gate(ctypes.Structure):
_fields_ = [('a', ctypes.POINTER(ctypes.c_double)),
('b', ctypes.POINTER(ctypes.c_double))]

def __init__(self, mydict:dict):
mask = [True, False, True, True, True, True, False, False, False, True]
a = np.ascontiguousarray(mydict['a'], dtype=np.double)
b = np.ascontiguousarray(mydict['b'], dtype=np.double)
setattr(self, 'a', a[0,:].ctypes.data_as(ctypes.POINTER(ctypes.c_double)))
setattr(self, 'b', b[0,:].ctypes.data_as(ctypes.POINTER(ctypes.c_double)))
self.size = 10

if __name__ == "__main__":

a = np.array([[1,2,3,4,5,6,7,8,9,10], [10,9,8,7,6,5,4,3,2,1]], dtype=np.double).T
b = a + 100

data = {'a': a, 'b': b}

mylib = ctypes.CDLL('./mwe.so')
mylib.printdouble.argstype = [ctypes.POINTER(s_gate), ctypes.c_int]
mylib.printdouble.restype = ctypes.c_void_p
print(f'Sending \n{a} and \n{b}')
gate = s_gate(data)

mylib.printdouble(ctypes.byref(gate), gate.size)
Выполнив этот код, я получил ожидаемый результат:

Код: Выделить всё

[[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]
[10.  9.  8.  7.  6.  5.  4.  3.  2.  1.]] and
[[101. 102. 103. 104. 105. 106. 107. 108. 109. 110.]
[110. 109. 108. 107. 106. 105. 104. 103. 102. 101.]]
gate->a[0] = 1.000000
gate->a[1] = 2.000000
gate->a[2] = 3.000000
gate->a[3] = 4.000000
gate->a[4] = 5.000000
gate->a[5] = 6.000000
...
gate->b[0] = 101.000000
gate->b[1] = 102.000000
gate->b[2] = 103.000000
gate->b[3] = 104.000000
gate->b[4] = 105.000000
gate->b[5] = 106.000000
...
Теперь давайте воспользуемся переменной маски в методе __init__ класса s_gate. Итак, давайте заменим строки 11 и 12 на:

Код: Выделить всё

setattr(self, 'a', a[0,mask].ctypes.data_as(ctypes.POINTER(ctypes.c_double)))
setattr(self, 'b', b[0,mask].ctypes.data_as(ctypes.POINTER(ctypes.c_double)))
self.size = sum(mask)
Результаты сейчас:

Код: Выделить всё

gate->a[0] = 0.000000
gate->a[1] = 0.000000
gate->a[2] = 0.000000
gate->a[3] = 0.000000
gate->a[4] = 0.000000
gate->a[5] = 0.000000
gate->b[0] = 101.000000
gate->b[1] = 103.000000
gate->b[2] = 104.000000
gate->b[3] = 105.000000
gate->b[4] = 106.000000
gate->b[5] = 110.000000
Все данные Gate.a обнуляются! Ожидаемый результат, конечно, [1, 3, 4, 5, 6, 10] для Gate.a
Что я пробовал до сих пор:
Используйте np.require, np.ascontigousarray, чтобы обеспечить непрерывный массив C, выполнить целочисленную индексацию вместо логической индексации, выполнить двухмерную логическую индексацию (

Код: Выделить всё

array[slices_xy]
вместо array[slice_x, срез_y]).

Используйте различные методы копирования, глубокого копирования и создайте промежуточные данные с помощью первого среза...
Ничего не получилось, как только появляется срез, который маскаописывает в этом коде (вместо :), появляется такое поведение. Что пошло не так?

Подробнее здесь: https://stackoverflow.com/questions/792 ... en-slicing
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»