exponenta event banner

Несовместимость с MATLAB в поддержке переменного размера для генерации кода

Несовместимость с MATLAB для скалярного расширения

Скалярное расширение - это метод преобразования скалярных данных в соответствии с размерами векторных или матричных данных. Если один операнд является скаляром, а другой нет, скалярное расширение применяет скаляр к каждому элементу другого операнда.

При создании кода применяются правила скалярного расширения, за исключением операций с двумя выражениями переменного размера. В этом случае оба операнда должны иметь одинаковый размер. Созданный код не выполняет скалярное расширение, даже если одно из выражений переменного размера оказывается скалярным во время выполнения. Поэтому при включенной проверке ошибок во время выполнения может возникнуть ошибка во время выполнения.

Рассмотрим эту функцию:

function y = scalar_exp_test_err1(u) %#codegen
y = ones(3);
switch u
    case 0
        z = 0;
    case 1
        z = 1;
    otherwise
        z = zeros(3);
end
y(:) = z;

При создании кода для этой функции генератор кода определяет, что z переменный размер с верхней границей 3.

При выполнении функции MEX с u равный 0 или 1, сгенерированный код не выполняет скалярное расширение, даже если z является скалярным во время выполнения. Поэтому при включенной проверке ошибок во время выполнения может возникнуть ошибка во время выполнения.

scalar_exp_test_err1_mex(0)
Subscripted assignment dimension mismatch: [9] ~= [1].

Error in scalar_exp_test_err1 (line 11)
y(:) = z;

Чтобы избежать этой проблемы, используйте индексирование, чтобы принудительно z является скалярным значением.

function y = scalar_exp_test_err1(u) %#codegen
y = ones(3);
switch u
    case 0
        z = 0;
    case 1
        z = 1;
    otherwise
        z = zeros(3);
end
y(:) = z(1);

Несовместимость с MATLAB при определении размера массивов N-D переменного размера

Для массивов N-D переменного размера: size функция может возвращать результат в сгенерированном коде, отличный от результата в MATLAB ®. В сгенерированном коде ,size(A) возвращает вывод фиксированной длины, так как он не отбрасывает конечные одиночные размеры N-D массивов переменного размера. Напротив, size(A) в MATLAB возвращает выходные данные переменной длины, поскольку они сбрасывают конечные одиночные размеры.

Например, если форма массива A является :?x:?x:? и size(A,3)==1, size(A) возвращает:

  • Трехэлементный вектор в сгенерированном коде

  • Двухэлементный вектор в коде MATLAB

Искусственные приемы

Если приложение требует, чтобы сгенерированный код возвращал тот же размер N-D массивов переменного размера, что и код MATLAB, рассмотрите один из следующих обходных путей:

  • Используйте форму с двумя аргументами size.

    Например, size(A,n) возвращает тот же ответ в сгенерированном коде и коде MATLAB.

  • Переписать size(A):

    B = size(A);
    X = B(1:ndims(A));

    Эта версия возвращает X с выходом переменной длины. Однако невозможно передать переменный размер X к конструкторам матрицы, таким как zeros для которых требуется аргумент фиксированного размера.

Несовместимость с MATLAB при определении размера пустых массивов

Размер пустого массива в созданном коде может отличаться от размера в исходном коде MATLAB. Размер может быть 1x0 или 0x1 в сгенерированном коде, но 0x0 в MATLAB. Поэтому не следует писать код, опирающийся на определенный размер пустых матриц.

Например, рассмотрим следующий код:

function y = foo(n) %#codegen
x = [];
i = 0;
while (i < 10)
    x = [5 x];
    i = i + 1;
end
if n > 0
    x = [];
end
y = size(x);
end

Для конкатенации требуется, чтобы ее операнды соответствовали размеру размера, который не является конкатенацией. В предыдущей конкатенации скалярное значение имеет размер 1x1 и x имеет размер 0x0. Для поддержки этого варианта использования генератор кода определяет размер для x как [1 x :?]. Потому что есть другое назначение x = [] после конкатенации размер x в сгенерированном коде 1x0 вместо 0x0.

Это поведение сохраняется при определении размера пустых символьных векторов, которые обозначаются как ''. Например, рассмотрим следующий код:

function out = string_size
out = size('');
end

Здесь значение out может быть 1x0 или 0x1 в сгенерированном коде, но 0x0 в MATLAB.

Сведения о несовместимости с MATLAB при определении размера пустого массива в результате удаления элементов массива см. в разделе Размер пустого массива в результате удаления элементов массива.

Работа

Если приложение проверяет, пуста ли матрица, используйте один из следующих обходных путей:

  • Перезаписать код для использования isempty вместо функции size функция.

  • Вместо использования x=[] для создания пустых массивов создайте пустые массивы определенного размера с помощью zeros. Например:

    function y = test_empty(n) %#codegen
    x = zeros(1,0);
    i=0;
    while (i < 10)
        x = [5 x];
        i = i + 1;
    end
    if n > 0
        x = zeros(1,0);
    end
    y=size(x);
    end

Несовместимость с MATLAB при определении класса пустых массивов

Класс пустого массива в сгенерированном коде может отличаться от его класса в исходном коде MATLAB. Поэтому не пишите код, опирающийся на класс пустых матриц.

Например, рассмотрим следующий код:

function y = fun(n)
x = [];
if n > 1
    x = ['a' x];
end
y=class(x);
end 
fun(0) прибыль double в MATLAB, но char в созданном коде. Когда оператор n > 1 имеет значение false, MATLAB не выполняется x = ['a' x]. Класс x является double, класс пустого массива. Однако генератор кода рассматривает все пути выполнения. Определяет, что на основе оператора x = ['a' x], класс x является char.

Работа

Вместо использования x=[] чтобы создать пустой массив, создайте пустой массив определенного класса. Например, использовать blanks(0) для создания пустого массива символов.

function y = fun(n)
x = blanks(0);
if n > 1
    x = ['a' x];
end
y=class(x);
end

Несовместимость с MATLAB при индексировании матриц

При индексировании матрица-матрица используется одна матрица для индексирования в другую матрицу. В MATLAB общее правило индексирования матрица-матрица состоит в том, что размер и ориентация результата соответствуют размеру и ориентации матрицы индекса. Например, если A и B - матрицы, size(A(B)) равняется size(B). Когда A и B являются векторами, MATLAB применяет специальное правило. Специальное правило векторно-векторной индексации заключается в том, что ориентация результата является ориентацией матрицы данных. Например, iA 1 на 5 и B равно 3 на 1, то A(B) 1 на 3.

Генератор кода применяет те же правила индексирования матрица-матрица, что и MATLAB. Если A и B являются матрицами переменного размера, для применения правил индексирования матрица-матрица, генератор кода предполагает, что size(A(B)) равняется size(B). Если, во время выполнения, A и B стать векторами и иметь разные ориентации, то предположение неверно. Поэтому при включенной проверке ошибок во время выполнения может возникнуть ошибка.

Чтобы избежать этой проблемы, используйте для индексирования оператор двоеточия. Например, предположим, что код намеренно переключается между векторами и регулярными матрицами во время выполнения. Можно выполнить явную проверку векторно-векторной индексации.

...
if isvector(A) && isvector(B)
    C = A(:);
    D = C(B(:));
else
    D = A(B);
end
...

Индексация в первой ветви указывает, что C и B(:) являются векторами времени компиляции. Поэтому генератор кода применяет правило индексации для индексации одного вектора другим вектором. Ориентация результата - это ориентация вектора данных, C.

Несовместимость с MATLAB при векторно-векторной индексации

В MATLAB специальным правилом для векторно-векторной индексации является то, что ориентация результата является ориентацией вектора данных. Например, если A 1 на 5 и B равно 3 на 1, то A(B) 1 на 3. Если, однако, вектор данных A является скаляром, то ориентация A(B) - ориентация вектора индекса B.

Генератор кода применяет те же правила векторно-векторной индексации, что и MATLAB. Если A и B являются векторами переменного размера, для применения правил индексирования генератор кода предполагает, что ориентация B соответствует ориентации A. Во время выполнения, если A скаляр и ориентация A и B не совпадают, тогда предположение неверно. Поэтому при включенной проверке ошибок во время выполнения может возникнуть ошибка во время выполнения.

Чтобы избежать этой проблемы, сделайте ориентации векторов совпадающими. Можно также индексировать отдельные элементы путем указания строки и столбца. Например, A(row, column).

Несовместимость с MATLAB в операциях индексирования матриц для генерации кода

Следующее ограничение применяется к операциям индексирования матрицы для генерации кода:

  • Инициализация следующего стиля:

    for i = 1:10
        M(i) = 5;
    end
    

    В этом случае размер M изменяется при выполнении цикла. Создание кода не поддерживает увеличение размера массива с течением времени.

    Для создания кода предварительно распределите M.

    M = zeros(1,10);
    for i = 1:10
        M(i) = 5;
    end
    

Следующее ограничение применяется к операциям индексирования матрицы для генерации кода, когда динамическое выделение памяти отключено:

  • M(i:j) где i и j изменение в цикле

    Во время создания кода память динамически не выделяется для размера выражений, которые изменяются при выполнении программы. Для реализации этого поведения используйте for-контуры, как показано на рисунке:

    ...
    M = ones(10,10);
    for i=1:10
        for j = i:10
            M(i,j) = 2*M(i,j);
        end
    end
    ...

    Примечание

    Матрица M должен быть определен перед входом в цикл.

Несовместимость с MATLAB при конкатенации матриц переменного размера

При создании кода при конкатенации массивов переменного размера размеры, которые не объединяются, должны точно совпадать.

Различия при индексировании массива ячеек переменного размера внутри конкатенации без элементов

Предположим, что:

  • c является массивом ячеек переменного размера.

  • Вы получаете доступ к содержимому c с помощью фигурных скобок. Например, c{2:4}.

  • Результаты включаются в конкатенацию. Например, [a c{2:4} b].

  • c{I} не возвращает элементы. Также c пуст или индексация внутри фигурных скобок приводит к пустому результату.

Для этих условий MATLAB пропускает c{I} из конкатенации. Например, [a c{I} b] становится [a b]. Генератор кода обрабатывает c{I} как пустой массив [c{I}]. Конкатенация становится [...[c{i}]...]. Эта конкатенация пропускает массив [c{I}]. Чтобы свойства [c{I}] совместимы с конкатенацией [...[c{i}]...], генератор кода назначает класс, размер и сложность [c{I}] согласно этим правилам:

  • Класс и сложность совпадают с базовым типом массива ячеек.

  • Размер второго измерения всегда равен 0.

  • Для остальных размеров размер Ni зависит от того, является ли соответствующее измерение в базовом типе фиксированным или переменным размером.

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

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

Предположим, что c имеет базовый тип с классом int8 и размер:10x7x8x:?. В созданном коде класс [c{I}] является int8. Размер [c{I}] является 0x0x8x0. Второе измерение равно 0. Первое и последнее измерения равны 0, поскольку эти измерения имеют переменный размер в базовом типе. Третий размер равен 8, поскольку размер третьего размера базового типа является фиксированным размером 8.

Внутри конкатенации, если индексация с фигурной скобкой массива ячеек переменного размера не возвращает элементов, генерируемый код может иметь следующие отличия от MATLAB:

  • Класс [...c{i}...] в сгенерированном коде может отличаться от класса в MATLAB.

    Когда c{I} не возвращает элементы, MATLAB удаляет c{I} из конкатенации. Поэтому c{I} не влияет на класс результата. MATLAB определяет класс результата на основе классов остальных массивов в соответствии с приоритетом классов. См. раздел Допустимые комбинации непохожих классов. В созданном коде класс [c{I}] влияет на класс результата общей конкатенации [...[c{I}]...] потому что генератор кода обрабатывает c{I} как [c{I}]. Описанные ранее правила определяют класс [c{I}].

  • В созданном коде размер [c{I}] может отличаться от размера в MATLAB.

    В MATLAB конкатенация [c{I}] является двойным значением 0x0. В сгенерированном коде ранее описанные правила определяют размер [c{I}].