exponenta event banner

Доступ к данным в типизированных, сотовых и структурных массивах

MATLAB ® Data API, используемый функциями C++ MEX, обеспечивает ту же семантику копирования при записи, что и функции, написанные непосредственно в 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 только массив, содержащийся в этой ячейке, не используется совместно, а не весь массив ячеек. Например, предположим, что массив ячейки A копируется в массив ячейки B. Значение каждой ячейки является общим.

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

В этом примере показано, как передать массив ячеек функции 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

API данных MATLAB определяет 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>, которые можно передать функциям, получающим доступ к значениям в поле. Ссылки позволяют получить значение поля, назначить новое значение полю и создать другой массив, ссылающийся на это значение. Например, этот код создает ссылку на поле, содержащее массив двойников.

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.

См. также

Связанные темы