Добавление вектора к пустой матрице MATLAB

Мне удалось устранить ошибку, обернув поток async.auto в new Promise() и разрешив / отклонив мой последний обратный вызов:

exports.updateLeaderboard = functions.database.ref('/contests/{dateString}/ladder/dayIsComplete').onWrite((event, context) => {
    const isComplete = event.after._data,
        contestType = 'ladder',
        dateString = context.params.dateString;

    if (isComplete !== true) {
        console.warn(`${contestType} for ${dateString} is not yet complete.`);

        return false;
    }

    return new Promise((resolve, reject) => {
        async.auto({
            fetchWinningPicks: cb => {
                return cb();
            },

            // ... Other stuff that I've now commented out

        }, err => {
            if (err) {
                reject();
            } else {
                resolve();
            }
        });
    });
};

Похоже, это исправляет обе мои проблемы, описанные выше.

17
задан Peter Mortensen 2 February 2011 в 19:42
поделиться

4 ответа

Используйте myPointMatrix = []; для инициализации матрицы.

Чем больше myPointMatrix , тем медленнее будет добавление. Он становится все медленнее и медленнее, поскольку каждый раз, когда вы добавляете точку, Matlab выделяет новую матрицу нового размера и копирует информацию из вашей старой матрицы + вашу новую точку в новую матрицу.

Тогда лучше инициализировать MyPointMatrix его окончательным размером и вставлять точки в заданные позиции в матрице.

14
ответ дан 30 November 2019 в 11:04
поделиться

Есть несколько способов добавить матрицу или вектор к любой матрице, пустой или нет. Многое зависит от размера матрицы и от того, как часто вы будете делать добавление. (Обратите внимание, что разреженные матрицы - это совершенно другое животное. С ними нужно разбираться отдельно.)

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

n = 10000;
tic
A = [];
for i = 1:n
  Ai = rand(1,3);
  A = [A;Ai];
end
toc

Elapsed time is 9.537194 seconds.

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

tic,rand(n,3);toc
Elapsed time is 0.008036 seconds.

Другие способы добавления похожи во времени. Например, вы можете добавить индексирование тоже.

A = [];
A(end+1,:) = rand(1,3);
A
A =
      0.91338      0.63236      0.09754

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

A = zeros(10000,3);
B = zeros(3,10000);

tic,for i = 1:100,A(end+1,:) = rand(1,3);end,toc
Elapsed time is 0.124814 seconds.

tic,for i = 1:100,B(:,end+1) = rand(3,1);end,toc
Elapsed time is 0.116209 seconds.

Проблема с любой операцией добавления вообще заключается в том, что MATLAB должен перераспределять память, требуемую для A, и делать это КАЖДЫЙ раз, когда матрица увеличивается в размере. Так как размер A растет линейно, общее требуемое время увеличивается квадратично с n. Таким образом, если бы мы удвоили размер n, то для динамически растущего A потребуется четыре раза больше времени. Именно из-за этого квадратичного поведения люди советуют вам предварительно распределять массивы MATLAB, когда они будут динамически расти. Фактически, если вы посмотрите на флаги mlint в редакторе, MATLAB предупредит вас, когда увидит, что это происходит.

Лучшим решением, если вы знаете конечный размер A, является предварительное выделение A для его окончательного размера. Затем просто внесите в индекс.

tic
A = zeros(n,3);
for i = 1:n
  A(i,:) = rand(1,3);
end
toc

Elapsed time is 0.156826 seconds.

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

Проблема в том, что иногда вы просто не знаете, сколько элементов у вас получится. Есть еще несколько приемов, которые можно использовать, чтобы избежать неприятного квадратичного роста.

Один прием состоит в том, чтобы угадать окончательный размер A. Теперь используйте индексирование, чтобы вставить новые значения в A, но внимательно следите за тем, когда новое записи будут выходить за границы A. Когда это только произойдет, удвойте размер A, добавив один большой блок нулей до конца. Теперь вернитесь к индексированию новых элементов в A. ведите отдельный подсчет того, сколько элементов было «добавлено». В самом конце этого процесса удалите неиспользуемые элементы. Это позволяет избежать большей части неприятного квадратичного поведения, поскольку только несколько шагов добавления будут выполнены. (Помните, что вы удваиваете размер A, когда вы должны сделать добавление.)

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

tic
C = {};
for i = 1:n
  C{end+1} = rand(1,3);
end
A = cat(1,C{:});
toc

Elapsed time is 3.042742 seconds.

Это заняло меньше времени, чем растущий массив. Зачем? Мы только строили массив указателей на клетки. Хорошая вещь об этом в том, что если каждый шаг добавления имеет переменное число строк, он все равно работает хорошо.

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

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

Несколько лет назад эта дискуссия возникла в группе новостей MATLAB, и было предложено несколько решений в этом направлении. Я разместил решения growdata & growdata2 в виде файлов на центральном файловом обмене MATLAB. Growdata2 использовал функциональные маркеры для решения проблемы:

tic
Ahandle = growdata2;
for i = 1:n
  Ahandle(rand(1,3))
end
% unpack the object into a normal array
A = Ahandle();
toc

Elapsed time is 1.572798 seconds.

В то время, это был несколько более быстрый подход к использованию постоянных переменных.

tic
growdata
for i = 1:n
  growdata(rand(1,3))
end
A = growdata;
toc

Elapsed time is 2.048584 seconds.

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

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

Ну да, это, безусловно, больше информации, чем первоначально запрашивалось, когда задавался вопрос. Возможно, кто-то что-то из этого получит.

28
ответ дан 30 November 2019 в 11:04
поделиться

Лучше всего предварительно выделить матрицу и использовать переменную цикла. Это должно быть значительно быстрее.

limit = 9;
myPointMatrix = nan((limit+1)^3,3);

loopVar = 1;
for x=0:limit
    for y=0:limit
        for z=0:limit
            myPointMatrix(loopVar,:) = [x y z];
            loopVar = loopVar + 1;
        end
    end
end
3
ответ дан 30 November 2019 в 11:04
поделиться

Я считаю, что решение, которое вы ищете, состоит в инициализации myPointMatrix в матрицу с 0 строками и 3 столбцами, т. е.

myPointMatrix = zeros(0, 3);

Тогда первое назначение

myPointMatrix = [myPointMatrix; tempPoint];

будет работать правильно, как и последующие. Эквивалентный способ написания присваивания - это

myPointMatrix(end+1,:) = tempPoint;

. Однако имейте в виду, что увеличение подобной матрицы неэффективно, и, как говорит AnnaR, инициализация myPointMatrix с использованием конечного размера ifs, если он известен, является лучшим решением. .

0
ответ дан 30 November 2019 в 11:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: