Fast way of computing all possible products of n matrices

조회 수: 10 (최근 30일)
Jonas Peschel
Jonas Peschel 2023년 1월 5일
댓글: Jonas Peschel 2023년 1월 11일
Hi, I have some n matrices (stored in a cell array) and want to compute all possible n! (max-plus-algebra-)products you can get by reordering them and everytime save the element in the bottom left corner. At the moment, I'm using the straight forward approach by iterating through all permutations and just calculating the product from start to end, which looks something like this:
for j = 1:n %initialise the n matrices
matrices{j} = some matrix;
end
interestingValue = zeros(1, factorial(n)); %array where to save the values
for i = 1:factorial(n) %iterate through all schedules
schedule = oneperm(n, i); %get the current schedule (order)
interestingValue(i) = computeProduct(matrices, schedule, n); %compute product for current schedule
end
with the computeProduct function looking like this:
function value = computeProduct(matrices, schedule, n)
product = matrices{schedule(1)}; %initialise with first matrix
for j = 2:n
product = max_plus_product(product, matrices{schedule(j)}); %compute product of current product with next matrix
end
value = product(end, 1);
My question would be how to speed up the calculation because performance is important for the project. I thought this approach I'm using right now is not really efficient because e.g. for all (n-2)! orders that would start with the matrices 1 and 2, you always compute the product of matrix 1 with matrix 2, instead of computing it just once because its always the same. So I thought about storing some intermediate results and using them later but I dont really know how to do this the most efficient way. Thats why I wanted to ask if there maybe already is a MATLAB function which is useful for this or if there is an other clever way.
Edit: mathemactical clarification for max-plus-multiplication: -> product of two n*n matrices A and B
Thank you very much for your help ^^
  댓글 수: 11
Bruno Luong
Bruno Luong 2023년 1월 7일
편집: Bruno Luong 2023년 1월 7일
My impression is if you bookeeping well you could reduce to two (and not n-1) max_plus_products by combinations using older results.
The problem is to store them if n is large. WHat are typical value of n?
If it is reasonable I might take a closer look.
Jonas Peschel
Jonas Peschel 2023년 1월 7일
Hi, at the moment a typical value of n would be maybe 9,10 but it would be desirable to also be able to go a bit higher maybe.

댓글을 달려면 로그인하십시오.

채택된 답변

Matt J
Matt J 2023년 1월 5일
편집: Matt J 2023년 1월 8일
This solution (note the attachments) does it in about 1 sec for a 20x20x10 set of single float matrices.
matrices=rand(20,20,10,'single');
tic;
M=matrices;
Mt=pagetranspose(M);
[N,~,n]=size(matrices);
s=ceil(n/2); t=n-s;
e=uint8(1:n);
Pleft=nchoosek(e,s);
Pright=flipud(nchoosek(e,t));
p=height(Pleft);
result=cell(1,p);
for i=1:p
matricesLeft=M(:,:,Pleft(i,:));
matricesRight=Mt(:,:,Pright(i,:));
partialLeft=permProducts(matricesLeft,N);
partialRight=permProducts(matricesRight,1).';
tmp=pageMaxPlus(partialLeft,partialRight);
result{i}=tmp(:).';
end
result=cell2mat(result).';
toc;
Elapsed time is 1.043404 seconds.
  댓글 수: 15
Bruno Luong
Bruno Luong 2023년 1월 11일
편집: Bruno Luong 2023년 1월 11일
Small experience with 3/2 split vs 2/3 split. The results look identical to me.
n=5;
% Fake data
M=rand(20,20,n,'single');
matrices=M;
tic;
M=matrices;
Mt=pagetranspose(M);
[N,~,n]=size(matrices);
s=ceil(n/2); t=n-s;
e=uint8(1:n);
Pleft=nchoosek(e,s);
Pright=flipud(nchoosek(e,t));
p=height(Pleft);
result=cell(1,p);
for i=1:p
matricesLeft=M(:,:,Pleft(i,:));
matricesRight=Mt(:,:,Pright(i,:));
partialLeft=permProducts(matricesLeft,N);
partialRight=permProducts(matricesRight,1).';
tmp=pageMaxPlus(partialLeft,partialRight);
result{i}=tmp(:).';
end
result=cell2mat(result).';
toc;
Elapsed time is 0.094892 seconds.
tic
M=matrices;
Mt=pagetranspose(M);
[N,~,n]=size(matrices);
s=floor(n/2); t=n-s;
e=uint8(1:n);
Pleft=nchoosek(e,s);
Pright=flipud(nchoosek(e,t));
p=height(Pleft);
result2=cell(1,p);
for i=1:p
matricesLeft=M(:,:,Pleft(i,:));
matricesRight=Mt(:,:,Pright(i,:));
partialLeft=permProducts(matricesLeft,N);
partialRight=permProducts(matricesRight,1).';
tmp=pageMaxPlus(partialLeft,partialRight);
result2{i}=tmp(:).';
end
result2=cell2mat(result2).';
toc
Elapsed time is 0.017183 seconds.
close all
plot(sort(result(:)),'bo')
hold on
plot(sort(result2),'r+')
%%
function AxB=pageMaxPlus(A,B)
%Page-wise implementation of max-plus multiplication
[mA,nA,pA]=size(A);
[mB,nB,pB]=size(B);
A = reshape(A, mA, nA, 1, pA);
B = reshape(B, 1, mB, nB, pB);
AxB = max(A+B,[],2);
AxB = reshape(AxB,mA,nB,max(pA,pB));
end
function result=permProducts(matrices, keyrow)
[N,~,n]=size(matrices);
if nargin<2, keyrow=N; end
numchunks=max(1,factorial(n)/factorial(8));
p=perms(1:n)';
p=reshape(p,n,[],numchunks);
P=width(p);
result=cell(1,numchunks);
for c=1:numchunks
M=reshape( matrices(:,:,p(:,:,c)) , N,n*N,P);
M=mat2cell(M,N,N*ones(1,n),P);
M{1}=M{1}(keyrow,:,:);
for s=1:n-1
M{s+1}=pageMaxPlus(M{s}, M{s+1});
end
result{c}=M{end}; %final result
end
result=squeeze(cell2mat(result)).';
end
Jonas Peschel
Jonas Peschel 2023년 1월 11일
Yes, really sorry to bother you. It works now for me also as it should be, I deleted a transpose which was necessary ^^

댓글을 달려면 로그인하십시오.

추가 답변 (2개)

Matt J
Matt J 2023년 1월 7일
편집: Matt J 2023년 1월 7일
Here's an alternative method that eliminates redundant computation, like you were hoping, using recursion. However, it doesn't seem to give a net performance advantage. On my laptop, it takes 380 sec. for a 20x20x10 set of single float matrices, which is quite a bit slower than my other answer.
clear, clc
matrices=rand(20,20,10,'single');
tic;
n=size(matrices,3);
result=cell(1,n);
for i=1:n
result{i}=recursionStep(matrices,matrices(:,1,i),i);
end
result=cell2mat(result);
result=result(end,:);
toc
Elapsed time is 380.316553 seconds.
function out=recursionStep(matrices,accum,sofar)
n=size(matrices,3);
if n==numel(sofar), out=accum; return ; end %end recursion
S=setdiff(1:n,sofar);
s=numel(S);
accum=pageMaxPlus(matrices(:,:,S), accum);
Sofars=[repmat(sofar,s,1),S(:)];
out=cell(1,s);
for i=1:s
out{i}=recursionStep(matrices,accum(:,:,i),Sofars(i,:));
end
out=cell2mat(out); out=out(:,:);
end
function out=pageMaxPlus(L,R)
%Page-wise implementation of max-plus multiplication
[mL,nL,~]=size(L);
[mR,nR,~]=size(R);
assert(mR==nL,'Size mismatch');
if mL<nR, implem='left'; else, implem='right'; end
switch implem
case 'left'
L=pagetranspose(L);
out=R(1:mL,:,:);
for i=1:mL
out(i,:,:)=max(L(:,i,:)+R,[],1);
end
case 'right'
R=pagetranspose(R);
out=L(:,1:nR,:);
for i=1:nR
out(:,i,:)=max(L+R(i,:,:),[],2);
end
end
end
  댓글 수: 1
Bruno Luong
Bruno Luong 2023년 1월 9일
I don't know if it's matter but this implementation of pageMaxPlus avoid the transpose
function out=pageMaxPlus(L,R)
%Page-wise implementation of max-plus multiplication
[mL,nL,~]=size(L);
[mR,nR,~]=size(R);
assert(mR==nL,'Size mismatch');
L = reshape(L, mL, nL, 1, []);
R = reshape(R, 1, mR,nR, []);
out = max(L+R,[],2);
out = reshape(out,mL,nR, []);
end
On my computer the code takes 121 sec

댓글을 달려면 로그인하십시오.


Bruno Luong
Bruno Luong 2023년 1월 9일
The more I try my idea, the more Matt's solution seem amazing to me.
Here is an algorithm that that build a set of product of all combinations (order matter) of k+1 matrices; starting from k=1, 2, up to n-1. If I count correctly there are exp(1)*factorial(n) matrix products to carried out, which seem to be an advance from the brute force algoritm, which requires (n-1)*factorial(n), for n>=4. However the timing is far, far away from Matt's solution.
Hat off for him.
n=9;
% Fake data
M=rand(20,20,n,'single');
n = size(M,3);
% C wil contain the result, it will have size m x m x factorial(n)
% We start with C of "product" of single matrices
C = M;
% This logical array will growed in row and keeps track of which matrix that has
% been accumulated in C
tobedo = (1:n).'~=(1:n);
for k=1:n-1
p = size(tobedo,1);
CTmp = cell(p,1);
for i=1:p % possible to do parfor
tbd = tobedo(i,:);
CTmp{i} = pageMaxPlus(C(:,:,i),M(:,:,tbd));
end
C = cat(3,CTmp{:});
m = n-k;
[i,j] = find(tobedo);
[i,is] = sort(i);
j = j(is);
h = repmat((1:m).',p,1);
tobedo = repelem(tobedo, m, 1);
idxdone = h + m*(i-1+p*(j-1));
tobedo(idxdone) = false;
end
%%
function AxB=pageMaxPlus(A,B)
%Page-wise implementation of max-plus multiplication
[mA,nA,~]=size(A);
[mB,nB,~]=size(B);
A = reshape(A, mA, nA, 1, []);
B = reshape(B, 1, mB, nB, []);
AxB = max(A+B,[],2);
AxB = reshape(AxB,mA,nB, []);
end
  댓글 수: 2
Matt J
Matt J 2023년 1월 10일
편집: Matt J 2023년 1월 10일
If I count correctly there are exp(1)*factorial(n) matrix products to carried out, which seem to be an advance from the brute force algoritm, which requires (n-1)*factorial(n), for n>=4. However the timing is far, far away from Matt's solution.
I'm not completely sure of the book-keeping, but here is one thing I notice:
% C wil contain the result, it will have size m x m x factorial(n)
So, my code doesn't compute an mxm matrix for each permutation. The OP said he is only interested in the lower left entry of the final matrices, so I throw away the first m-1 rows of the first matrix in the sequence, thereby reducing all the matrix products to vector-matrix products. This requires at least a factor of O(m) less computation and memory.
Also, because of the divide and conquer, there are (n-1)*factorial(n)/factorial(n/2) vector-matrix products.
Also, because the products are vector-matrix products, my implementation of pageMaxPlus with pagetranspose might be cheaper than the approach you take with implicit expansion. Transposition of a multi-page vector is really only a reshape() operation.
Bruno Luong
Bruno Luong 2023년 1월 10일
편집: Bruno Luong 2023년 1월 10일
Oh thanks @Matt J; I miss the trick of not computing the whole matrix, here is the version with that simplification
n=9;
% Fake data
M=rand(20,20,n,'single');
n = size(M,3);
% This logical array will growed in row and keeps track of which matrix that has
% been accumulated in C
tobedo = true(1,n);
% Define what elements of the final cumulative matrices we want
selected_row = size(M,1); % EDIT fix bug
selected_col = 1;
% C wil contain the result, it will have size m x 1 x factorial(n)
% We start with C of "product" of single matrices
C = M(selected_row,:,:);
p = 1;
for k=1:n-1
% Update the tobedo array
m = n-k+1;
[j,i] = find(tobedo.');
h = repmat((1:m)',p,1);
idxdone = h + m*(i-1+p*(j-1));
tobedo = repelem(tobedo, m, 1);
tobedo(idxdone) = false;
p = p*m;
CTmp = cell(p,1);
for i=1:p % possible to do parfor
tbd = tobedo(i,:);
CTmp{i} = pageMaxPlus(C(:,:,i),M(:,:,tbd));
end
C = cat(3,CTmp{:});
end
% extract and reshape to get final result, row vector of length factorial(n)
result = reshape(C(:,selected_col,:), 1, []);
%%
function AxB=pageMaxPlus(A,B)
%Page-wise implementation of max-plus multiplication
[mA,nA,pA]=size(A);
[mB,nB,pB]=size(B);
A = reshape(A, mA, nA, 1, pA);
B = reshape(B, 1, mB, nB, pB);
AxB = max(A+B,[],2);
AxB = reshape(AxB,mA,nB,max(pA,pB));
end

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Startup and Shutdown에 대해 자세히 알아보기

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by