Доступ к данным во введенном, ячейке и массивах структур

MATLAB® API данных, используемый MEX-функциями C++, обеспечивает ту же семантику копирования при записи, используемую функциями, написанными непосредственно в MATLAB. MEX-функция может скопировать массив данных, переданный ему, но эта копия является разделяемой копией исходной переменной. Отдельная копия данных сделана, когда MEX-функция изменяет значения в массиве.

Когда вы вызываете MEX-функцию, matlab::data::Array входные параметры являются совместно использованными копиями переменных MATLAB, переданных MEX-функции. Разделяемые копии обеспечивают преимущество когда MEX-функция:

  • Не изменяет большой массив, переданный MEX-функции.

  • Изменяет определенные поля структуры, которая передается как вход, не делая копию целой структуры.

  • Изменяет ячейку в массиве ячеек, который передается как вход, не вызывая глубокую копию массива ячеек

  • Изменяет свойство объекта, которое передается как вход, не делая глубокую копию объекта.

Разделяемые копии

Этот пример кода извлекает выгоду из использования разделяемых копий при вычислении среднего значения матрицы изображений. Копирование входного массива к const matlab::data::TypedArray<T>, то, которое поддерживает итераторы, включает использование основанного на области значений for цикл, чтобы выполнить вычисление, но гарантирует, что массив не копируется.

#include "mex.hpp"
#include "mexAdapter.hpp"

using matlab::mex::ArgumentList;
using namespace matlab::data;

class MexFunction : public matlab::mex::Function {
    ArrayFactory factory;
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {
        double sm = 0;
        const TypedArray<uint8_t> inArray = inputs[0];
        for (auto& elem : inArray) {
            sm += elem;
        }
        outputs[0] = factory.createScalar(sm / inArray.getNumberOfElements());
    }
};

Сохраните исходный код MEX-функции в файле под названием aveImage.cpp. Можно использовать эту функцию, чтобы найти среднее значение массива топографических данных. Загрузите topo.mat файл в рабочее пространство MATLAB и передачу массив данных к MEX-функции.

mex aveImage.cpp
load topo
d = uint8(topo); % convert data to use aveImage
m = aveImage(d)
m = 73.5487

Измените массив ячеек в MEX-функции

Когда вы передаете массив ячеек MEX-функции, ее представлению MATLAB Data API, matlab::data::CellArray, по существу matlab::data::Array это содержит matlab::data::Array в каждой ячейке. Этот проект позволяет каждому содержавшему массиву быть разделяемой копией, пока не изменено.

Когда вы изменяете ячейку массива ячеек в MEX-функции, только массив, содержавшийся в той ячейке, не разделен, не целый массив ячеек. Например, предположите, что вы копируете массив ячеек в массив ячеек B. Значение каждой ячейки совместно используется.

Each cell in array A maps to a cell in array B.

Если вы изменяете Cell1 в массиве ячеек B, массив в той ячейке больше не совместно используется с Cell1 в массиве ячеек A. Однако значения всех других ячеек остаются разделяемыми так, чтобы целый массив ячеек не должен был быть скопирован.

Each cell except Cell1 in array A maps to a cell in array B.

В этом примере показано, как передать массив ячеек MEX-функции и изменить одну ячейку в массиве ячеек, не вызывая копии данных в других ячейках. Пример загружает данные изображения в рабочее пространство MATLAB и создает массив ячеек, который содержит данные изображения, заголовок и палитру.

load durer
whos
  Name           Size               Bytes  Class 

  X            648x509            2638656  double
  caption        2x28                 112  char  
  map          128x3                 3072  double 

Присвойте каждую переменную различной ячейке.

durerCell{1} = X;
durerCell{2} = caption;
durerCell{3} = map;

Эта MEX-функция использует std::move перемещать входной массив ячеек в matlab::data::CellArray, который обеспечивает доступ к отдельным ячейкам. Единственные измененные данные являются заголовком, который хранится в одной ячейке массива ячеек. Изменить ту ячейку:

  • Получите matlab::data::Reference<TypedArray<T>> ссылка на массив в ячейке, содержащей заголовок.

  • Присвойте новое значение ссылке как matlab::data::CharArray потому что возвращенное значение является вектором символов MATLAB.

#include "mex.hpp"
#include "mexAdapter.hpp"

using matlab::mex::ArgumentList;
using namespace matlab::data;

class MexFunction : public matlab::mex::Function {
    ArrayFactory factory;
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {
        checkArguments(inputs);
        CellArray imageCell = std::move(inputs[0]);
        TypedArrayRef<char16_t> cellRef = imageCell[1];
        cellRef = factory.createCharArray("Albrecht Durer's Melancolia with a magic square" );
        outputs[0] = imageCell;
    }

    void checkArguments(ArgumentList inputs) {
        std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
        if (inputs[0].getType() != ArrayType::CELL) {
            matlabPtr->feval(u"error", 0, std::vector<Array>
                ({ factory.createScalar("Input must be cell array") }));
        }
    }
};

Сохраните этот код в файле с именем modifyCellArray.cpp, создайте файл MEX и вызовите функцию.

mex modifyCellArray.cpp
durerCell = modifyCellArray(durerCell);

Возвращенный массив ячеек содержит новый символьный массив, присвоенный в MEX-функции.

durerCell{2}
ans =

    'Albrecht Durer's Melancolia with a magic square'

Для получения дополнительной информации о работе с массивами ячеек смотрите C++ Массивы ячеек.

Измените структуру в MEX-функции

MATLAB Data API задает matlab::data::StructArray представлять MATLAB struct массивы. Каждое поле в StructArray самостоятельно содержит массив. Поэтому можно изменить поле StructArray переданный MEX-функции, не заставляя целый массив быть скопированным. Поля, не измененные, остаются разделяемыми с полями входного массива.

StructArray класс обеспечивает функции членства, чтобы получить доступ к полям структуры:

  • getFieldNames возвращает начальные и конечные итераторы, обеспечивающие доступ к именам полей.

  • getNumberOfFields возвращает количество полей в структуре.

Например, можно сгенерировать вектор из имен полей и использовать эти имена, чтобы получить доступ к данным в структуре. Этот код принимает, что поле содержит массив типа double.

auto fields = myStruct.getFieldNames();
std::vector<matlab::data::MATLABFieldIdentifier> fieldNames(fields.begin(), fields.end());
// Get the data from one field
matlab::data::TypedArray<double> field1 = myStruct[0][fieldNames[0]]

Присвойте новые значения полю путем создания массива правильного типа.

myStruct[0][fieldNames[0]] = factory.createArray<double>({ 1,5 }, { 1, 2, 3, 4, 5 });

Создайте ссылку на поле структуры с помощью matlab::data::Reference<T>, который можно передать функциям, которые получают доступ к значениям в поле. Ссылки позволяют вам получить значение поля, присвоить новое значение полю и создать другой массив, который относится к тому же значению. Например, этот код создает ссылку на поле, содержащее массив типа double.

auto fields = myStruct.getFieldNames();
std::vector<matlab::data::MATLABFieldIdentifier> fieldNames(fields.begin(), fields.end());
matlab::data::TypedArrayRef<double> field1Reference = myStruct[0][fieldNames[0]]

Присвойте новые значения полю с помощью этой ссылки.

field1Reference = factory.createArray<double>({ 1,5 }, { 1, 2, 3, 4, 5 });

Присвойте полю структуры

Этот пример передает структуру MATLAB MEX-функции. Структура содержит два больших поля данных и два поля, чтобы содержать скалярные значения, присвоенные MEX-функцией. MEX-функция вычисляет среднее значение для чисел в каждом массиве и присваивает эти значения Average поле соответствующей структуры.

Этот код MATLAB создает массив структур и передает его MEX-функции, созданной из modifyStruct.cpp файл описан здесь.

s = struct('Average',{[],[]},...
   'Data',{rand(1,1000),randi([1,9],1,1000)});
s = modifyStruct(s);

Вот MexFunction::operator() функция. Это выполняет эти операции:

  • Вызовите checkArgument функционируйте, чтобы проверять вводы и выводы на размер и тип.

  • Присвойте вход matlab::data::StructArray переменная.

  • Вызовите calcMean функция, чтобы вычислить средние значения.

  • Присвойте обновленный массив структур MEX-функции выход.

#include "mex.hpp"
#include "mexAdapter.hpp"

using matlab::mex::ArgumentList;
using namespace matlab::data;

class MexFunction : public matlab::mex::Function {
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {
        checkArguments(outputs, inputs);
        StructArray inStruct(inputs[0]);
        calcMean(inStruct);
        outputs[0] = inStruct;
    }

checkArguments функция выполняет эти проверки:

  • Количество входных параметров равняется тому.

  • Количество выходных параметров не больше того.

  • Вход является массивом структур MATLAB.

    void checkArguments(ArgumentList outputs, ArgumentList inputs) {
        std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
        ArrayFactory factory;
        if (inputs.size() != 1) {
            matlabPtr->feval(u"error", 0,
                std::vector<Array>({ factory.createScalar("One input required") }));
        }
        if (outputs.size() > 1) {
            matlabPtr->feval(u"error", 0,
                std::vector<Array>({ factory.createScalar("Too many outputs specified") }));
        }
        if (inputs[0].getType() != ArrayType::STRUCT) {
            matlabPtr->feval(u"error", 0,
                std::vector<Array>({ factory.createScalar("Input must be structure") }));
        }
    }

calcMean функция вычисляет среднее значение для каждого значения чисел в Data поля и присвоения эти значения к Average поле соответствующей структуры.

    void calcMean(StructArray& inStruct) {  
        ArrayFactory factory;
        auto fields = inStruct.getFieldNames();
        std::vector<MATLABFieldIdentifier> fieldNames(fields.begin(), fields.end());
        double sm = 0;
        for (auto i = 0; i < 2; i++) {
            const TypedArray<double> data = inStruct[i][fieldNames[1]];
            for (auto& elem : data) {
                sm += elem;
            }
            inStruct[i][fieldNames[0]] = factory.createScalar(sm / data.getNumberOfElements());
        }
    }
};

Пример ячейки и массивов структур

Для связанного примера, который использует ячейку и массивы структур, откройте этот исходный файл в редакторе MATLAB phonebook.cpp.

Смотрите также

Похожие темы