Несовместимость с 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 применяет специальное правило. Специальное правило индексации вектор-вектор состоит в том, что ориентация результата является ориентацией матрицы данных. Например, я A 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}].