Несколько матриц в Matlab без рекурсии - PullRequest
3 голосов
/ 10 мая 2009

Я должен написать скрипт Matlab, который делает это:

Вводится 2 матрицы, A (m x n) и D (m x 1) Выход представляет собой матрицу C (m x n). C рассчитывается так:

function c = scanrow(a,d)
[rows columns] = size(d);
for i=1:columns
a(i,:) = a(i,:).*d(i);   
end
c = a;
end

Требование не использовать рекурсию. Я понятия не имею, чтобы решить эту проблему. Рад, что вы можете помочь. Спасибо.

Ответы [ 5 ]

10 голосов
/ 10 мая 2009

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

a = 1:5;
b = magic(5);

c = bsxfun(@times,a,b);

Но будьте осторожны - это доступно только в относительно новых версиях MATLAB. -pete

3 голосов
/ 11 мая 2009

(Я отвечу, несмотря на то, что это домашняя работа. Я думаю, что многие не понимают, почему был создан bsxfun.)

Есть и другие решения по умножению. Типичными являются использование repmat, цикл или умножение на диагональную матрицу. Лучше, если диагональная матрица сделана разреженной матрицей. Тем не менее, bsxfun определенно является правильным решением. Он был написан для решения подобных проблем. Проблема в том, что когда вы делаете такие вещи, как

A = magic(3) + 5

MATLAB понимает, что он должен добавить 5 к каждому элементу магии (3). Точно так же, когда вы делаете

A = magic(4).*2

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

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

A = magic(3).*rand(1,3)

В прошлом решением было использовать repmat. Но когда вы используете repmat для явного расширения вектора в матрицу, вы съедаете много памяти, чтобы решить проблему векторизованным способом. Да, для векторизации характерно обменять память на время в MATLAB, но это может быть плохо, если вы уже ограничены в памяти и работаете над большой проблемой. Заставлять MATLAB (и вашу ОС) перемещаться в виртуальную память - очень плохая идея, когда в этом нет необходимости. (Любое решение приемлемо для крошечной проблемы.)

Итак, когда вы пытаетесь умножить массив типа magic (3) на строку или вектор столбца, должен ли MATLAB понять, что он должен выполнять неявное расширение вектора в массив? Или MATLAB должен предположить, что вы сделали ошибку, и пометить это как таковой? Эта проблема, известная как расширение одноэлементных измерений, является проблемой. (Одноэлементное измерение находится в векторе, где одно из измерений было 1.) Возвращение сообщения об ошибке является хорошей идеей для многих пользователей, поскольку часто это сигнализирует о том, что ошибка найдена, ошибка допущена. Простое автоматическое расширение всех одноэлементных измерений для решения рассматриваемой проблемы может показаться опасным. На самом деле, было много дискуссий о том, что делать. Например, должен ли MATLAB создать предпочтение, в котором пользователь мог бы разрешить расширение одноэлементных измерений в своей версии MATLAB? Это было бы плохой идеей, так как это сделало бы код непереносимым между системами.

Кроме того, если бы базовые операторы MATLAB были изменены, чтобы всегда расширять все одноэлементные измерения, то код MATLAB был бы сильно непереносимым к более старым версиям.

Мы даже обсуждали создание целого нового набора операторов MATLAB, таких как. *, Параллельно с *, для выполнения операции при расширении одноэлементных измерений. Это тоже была плохая идея, и ее по праву избегали.

Решением было создание BSXFUN (Binary Scalar eXpansion FUNction), чтобы эта операция могла быть выполнена эффективно, когда это необходимо. В файлообменнике обнаружен bsxfun, который позволяет пользователям старых версий получить такое поведение, поэтому переносимость поддерживается как можно лучше. BSXFUN позволяет работать с любой парой аргументов, применяя пользовательскую функцию между ними. Так что это позволяет вам делать такие вещи:

A = rand(5,1);
B = rand(1,3);
C = bsxfun(@plus,A,B);

для создания матрицы 5x3 суммы элементов в каждом из A и B. Вы также можете использовать любую функцию в качестве первого операнда, поэтому BSXFUN очень мощный.

Наконец, еще один способ взглянуть на BSXFUN - это вариация внешнего продукта. Таким образом, эта операция в MATLAB прекрасно определена:

A = rand(5,1);
B = rand(1,3);
C = A*B;

Однако, любая из этих операций

D = A-B;
E = A^B;

приведет к ошибке. BSXFUN позволяет вам делать их эффективно, не занимая объем памяти при расширении синглтона.

D = bsxfun(@minus,A,B);
E = bsxfun(@power,A,B);
3 голосов
/ 10 мая 2009

Если проблема заключается в том, чтобы «умножить каждый элемент в каждой строке A на соответствующий элемент в соответствующей строке D», я бы предложил следующее:

dd = repmat(d, 1, size(a, 2))
c = a.*dd

Пример:

>> a = [1 2; 3 4; 5 6];
>> d = [1 2 3]';
>> dd = dd = repmat(d, 1, size(a, 2))
dd = 
     1   1
     2   2
     3   3
>> a.*dd
ans =
     1   2
     6   8
     15  18
0 голосов
/ 10 мая 2009

Вы уверены, что код, который вы указали в вопросе, верен? Вот что он делает:

Я предполагаю, что входы a и d представляют матрицы A (размер m-by-n) и D (размер м-на-1), что вы упомянули. Поскольку вы определили d как всегда имеющий 1 столбец, цикл for не нужен, поскольку он будет повторяться только один раз. Один проход через цикл просто умножит значения в первой строке a на первое значение в d . Поэтому весь фрагмент кода в вопросе можно заменить следующим:

c = a;
c(1,:) = c(1,:).*d(1);
0 голосов
/ 10 мая 2009

Может быть vectorize() - это то, что вы хотите -> Руководство по векторизации кода

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...