Оптимизирует ли неявное вещание MATLAB на основе окружающего кода?

Заданный сегодня вопрос дал неожиданный результат в отношении неявного создания массива:

array1 = 5*rand(496736,1);
array2 = 25*rand(9286,1);
output = zeros(numel(array1), numel(array2)); % Requires 34GB RAM
output = zeros(numel(array1), numel(array2),'logical'); % Requires 4.3GB RAM
output = abs(bsxfun(@minus, array1.', array2)) <= 2; % Requires 34GB RAM
output = pdist2(array1(:), array2(:)) <= 2; % Requires 34GB RAM

Все идет нормально. Массив, содержащий 496736*9286 двойных значений, должен занимать 34 ГБ, а логический массив, содержащий такое же количество элементов, требует всего 4,3 ГБ (в 8 раз меньше). Это происходит для последних двух, потому что они используют промежуточную матрицу, содержащую все пары расстояний с двойной точностью, что требует полных 34 ГБ, тогда как логическая матрица предварительно выделяется напрямую как просто логические и требует 4,3 ГБ.

Удивительная часть начинается здесь:

output = abs(array1.' - array2); % Requires 34GB RAM
output = abs(array1.' - array2) <= 2; % Requires 4.3GB RAM ?!?

Какая?!? Почему неявное расширение не требует тех же 34 Гб оперативной памяти за счет создания промежуточной двойной матрицы output = abs(array1.' - array2)?

Это особенно странно, поскольку неявное расширение — это, как я понял, короткий способ написания старых bsxfun решений. Так почему же bsxfun создает полную 34-гигабайтную матрицу, а неявное расширение — нет?

MATLAB каким-то образом распознает, что результат операции должен быть логической матрицей?


Все тесты проводились на MATLAB R2018b, Ubuntu 18.04, 16 ГБ ОЗУ (т.е. ошибка массивов 34 ГБ)


person Adriaan    schedule 16.09.2019    source источник
comment
@HansHirse Это действительно очень интересный намек. Однако, что касается скорости выполнения, то я не вижу большой разницы. Я проверял это в прошлом, и разница была небольшой и заметной только для небольших массивов. Это соответствует что сказал Стив Эддинс. Я только что повторил тесты в R2019a, и результаты такие же.   -  person Luis Mendo    schedule 16.09.2019
comment
Возможно ли, что JIT вычисляет составные операторы поэлементно? (Я имею в виду, что d=a+b+c вычисляется не как tmp=a+b; d=tmp+c, а как d(i)=a(i)+b(i)+c(i)? Кто-нибудь может проверить это (например, максимальное использование памяти)?   -  person Cris Luengo    schedule 16.09.2019
comment
сокращение array1 до четверти его длины позволяет выполнять код на моей машине, и он НЕ использует ту же ОЗУ, много ОЗУ для большого количества вывода, гораздо меньше ОЗУ для логического вывода. Я предполагаю, что поэлементная теория верна   -  person Yuval Harpaz    schedule 16.09.2019
comment
Некоторые подсказки от julia. Возможно, MATLAB выбрал другие методы, такие как разделение данных и вычисление блоков по кусок.   -  person rahnema1    schedule 16.09.2019
comment
Я предполагаю, что @CrisLuengo прав, Matlab, вероятно, делает что-то близкое к output = bsxfun(@(x,y)(abs(x-y)<2),array1.',array2). Если вы поместите оператор сравнения внутри анонимной функции, bsxfun должен потреблять меньше памяти.   -  person obchardon    schedule 16.09.2019
comment
@CrisLuengo, что вполне вероятно, поскольку такие составные инструкции часто доступны в виде примитивов ALU в современных процессорах.   -  person Ander Biguri    schedule 16.09.2019
comment
@AnderBiguri Верно. Кроме того, это было бы большой победой для интерпретатора/JIT, поскольку он уменьшает объем используемой промежуточной памяти и улучшает использование кеша.   -  person Cris Luengo    schedule 16.09.2019
comment
Каков следующий этап этой оптимизации? x = ones(1e200, 1e300); clear x работает в кратчайшие сроки?   -  person Luis Mendo    schedule 16.09.2019
comment
@LuisMendo: это то, что должен делать хороший оптимизирующий компилятор. Нет смысла выполнять оператор без эффекта.   -  person Cris Luengo    schedule 16.09.2019
comment
@cris Я всегда думал, что интерпретатор выполняет операторы независимо друг от друга. Меня беспокоит отсутствие осторожности   -  person Luis Mendo    schedule 16.09.2019
comment
Было бы интересно посмотреть, что на самом деле выполняет MATLAB. Я много работал с генерацией кода на C, там явно все проще. Просто сравните свой первоначальный код C с оптимизированным и, если есть сомнения, запустите обе версии в своем наборе тестов.   -  person Daniel    schedule 19.02.2020