dll инициализация вектора с помощью ctypes данных

Вопрос или проблема

Я хочу перенести данные из Python в библиотеку C++ DLL для работы с матрицами, а затем получить данные обратно. Я создаю массив (c_double * 102)(c_double(0)) в Python (первый и второй элементы массива говорят о размере матрицы).
В Python у меня есть правильные данные (проверено с помощью более простой функции, такой как сумма членов массивов и возврат этой суммы), но когда я пытаюсь заполнить матрицу, она всегда заполняется нулями.

(код на Python):

В Python у меня есть класс, который переводит список (list()) в (c_types * 102)(0) для соединения с моей DLL, и это вроде работает правильно. Также я использую указатели для передачи данных.

class tu_matrix:
    body = (c_double * 102)(c_double(0))
    ptr = POINTER(c_double * 102)

    def load(self, data = list(list())):
        self.data = data
        self.n_size = len(data)
        self.m_size = len(data[0])
        for i in range(self.n_size):
            for j in range(self.m_size):
                self.body[2+i*self.m_size + j] = c_double(data[i][j])
        ptr = pointer(self.body)


def calcMatrix():
    tu_matrix1.load(matrix1)
    tu_matrix2.load(matrix2)

    # Аргументы для matrix_sum
    matrix_lib.matrix_sum.argtypes = [POINTER(c_double * 102), 
                                      POINTER(c_double * 102)]  

    # Тип возвращаемого значения matrix_sum
    matrix_lib.matrix_sum.restype = POINTER(c_double * 102) 

    # Получение указателей на массивы
    ptr1 = pointer(tu_matrix1.send())  # указатель на первый массив
    ptr2 = pointer(tu_matrix2.send())  # указатель на второй массив

    # Вызов функции, передающей массивы
    result_ptr = matrix_lib.matrix_sum(ptr1, ptr2)

    result_array = result_ptr.contents  # получение содержимого из указателя

    # перевод в список
    list_of_lists = []
    for i in range(0, 102, 10):  
        sublist = [result_array[i + j] for j in range(10) if i + j < 102]
        list_of_lists.append(sublist)

    print(list_of_lists)

    return result_ptr

(функция для преобразования данных):

В моем C++ коде я заполняю вектор данными из Python и в этот момент ловлю ошибку с некорректными данными. Все заполнено нулями, когда я пробую использовать, я думаю, что проблема связана с личным классом, потому что простые массивы или типы данных работают нормально.

template<typename val_type>
void matrix<val_type>::arr_to_matrix(double arr[102]) {

    this->body.clear();
    for (int i = 0; i < (int)arr[0]; i++) {
        vector<double> line;
        for (int j = 0; j < (int)arr[1]; j++) {
            line.push_back(arr[2 + i * (int)arr[1] + j]);
        }
        this->body.push_back(line);
    }

    this->size_n = (int)arr[0];
    this->size_m = (int)arr[1];
    this->empty_matrix = false;
    this->zero_matrix = false;
    this->was_calc_det = false;
}

(функция dll):

static double result[102];

extern "C" __declspec(dllexport) double* matrix_sum(double arr1[102], double arr2[102]) {
    // Сумма матриц для данных c-types от Python
    matrix<double> m1({ { 1,1 }, { 2,2 } });
    matrix<double> m2({ { 1,1 }, { 2,2 } });

    m1.arr_to_matrix(arr1);
    m2.arr_to_matrix(arr2);

    m1 += m2;

    int n = m1.line_size();
    int m = m1.column_size();

    result[0] = n;
    result[1] = m;

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            result[2 + i * m + j] = m1.val(i, j);
        }
    }

    return result;
}

Если я удалю строки m1.arr_to_matrix(arr1); m2.arr_to_matrix(arr2);, то он инициализируется с помощью initlist и работает правильно, но в этом случае теряется весь смысл создания интерфейса с Python. Когда я запускаю программу без Python и проверяю, она работает корректно:

(это работает)

int main () {
    double* arr1 = new double[102];
    double* arr2 = new double[102];

    for (int i=0; i<6; i++) {
        arr1[i] = 2;
        arr2[i] = 2;
    }

    arr1 = matrix_sum(arr1, arr2);

    for (int i = 0; i<6; i++) {
        std::cout << arr1[i] << " ";
    }

}

Ответ или решение

Для успешной инициализации данных c Python в библиотеку C++ через DLL с использованием ctypes, необходимо учесть несколько ключевых моментов. Рассмотрим предоставленный код более подробно и выявим возможные причины возникновения проблемы с заполнением массива нулями.

1. Структура класса tu_matrix

Класс tu_matrix, который вы создали, корректно инициализирует массив размером 102. Однако есть некоторые моменты, которые стоит улучшить:

class tu_matrix:
    body = (c_double * 102)(c_double(0))
    ptr = POINTER(c_double * 102)

    def load(self, data=list(list())):
        self.n_size = len(data)
        self.m_size = len(data[0])
        for i in range(self.n_size):
            for j in range(self.m_size):
                self.body[2 + i * self.m_size + j] = c_double(data[i][j])

    def send(self):
        return pointer(self.body)

Убедитесь, что метод send, который вы используете для передачи указателя, возвращает корректный указатель на вашу структуру. Рекомендуется переопределить метод send для лучшего понимания.

2. Передача указателей в функцию matrix_sum

В функции calcMatrix есть небольшая ошибка при передаче указателей. Вам не нужно вызывать pointer от уже созданного указателя:

ptr1 = pointer(self.body)
ptr2 = pointer(self.body)

Обновите вызов функции, чтобы передать указатели непосредственно.

3. Вызов функции в C++

В коде C++ функция matrix_sum ожидает массивы, переданные из Python. Убедитесь, что вы правильно обрабатываете полученные данные:

extern "C" __declspec(dllexport) double* matrix_sum(double arr1[102], double arr2[102]) {
    matrix<double> m1, m2;
    m1.arr_to_matrix(arr1);
    m2.arr_to_matrix(arr2);
    // Производим сложение матриц
    m1 += m2;

    // Установка результатов
    result[0] = m1.line_size();
    result[1] = m1.column_size();

    for (int i = 0; i < m1.line_size(); i++) {
        for (int j = 0; j < m1.column_size(); j++) {
            result[2 + i * m1.column_size() + j] = m1.val(i, j);
        }
    }

    return result;
}

4. Проверка на ошибки

Когда вы работаете с памятью и указателями, важно отлаживать код на наличие возможных ошибок. Рекомендуется добавлять отладочные сообщения (например, printf или std::cout) для проверки содержимого массивов, прежде чем использовать их. Это поможет выявить проблему на ранней стадии.

5. Заключение

Если вы всё еще получаете нулевые значения, проверьте следующие моменты:

  • Убедитесь, что массив правильно инициализируется и заполняется перед передачей в C++.
  • Проверьте соответствие типов данных между Python и C++. Например, в Python c_double должен соответствовать double в C++.
  • Убедитесь, что передача указателей происходит корректно, и данные не теряются в процессе передачи.

Если все вышеперечисленное выполнено, ваша функция должна работать корректно и возвращать ожидаемые результаты. Не забывайте также тестировать все ключевые части кода по отдельности для изоляции потенциальных ошибок.

Оцените материал
Добавить комментарий

Капча загружается...