MATLAB® Data 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()); } };
Можно использовать эту функцию, чтобы найти среднее значение массива топографических данных. Загрузите topo.mat
файл в рабочее пространство MATLAB и передачу массив данных к MEX-функции. Сохраните исходный код MEX-функции в файле под названием aveImage.cpp
.
mex aveImage.cpp load topo m = aveImage(topo) m = -1.8948e+03
Когда вы передаете массив ячеек MEX-функции, ее представлению MATLAB Data API, matlab::data::CellArray
, по существу matlab::data::Array
это содержит matlab::data::Array
в каждой ячейке. Этот проект позволяет каждому содержавшему массиву быть разделяемой копией, пока не изменено.
Когда вы изменяете ячейку массива ячеек в MEX-функции, только массив, содержавшийся в той ячейке, не разделен, не целый массив ячеек. Например, предположите, что вы копируете массив ячеек в массив ячеек 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++ Массивы ячеек.
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>
, который можно передать функциям, которые получают доступ к значениям в поле. Ссылки позволяют вам получить значение поля, присвоить новое значение полю и создать другой массив, который относится к тому же значению. Например, этот код создает ссылку на поле, содержащее массив, удваивается.
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
.
matlab::data::MATLABFieldIdentifier