1

It is very easy to collapse several matrices (of differing sizes) into a single 1xN vector:

vec = [ A(:)', B(:)', C(:)' ];

... but how can I now go the other way, i.e. recover U,V,W from vec?

I could collect the sizes of A, B, C:

sizes = [ size(A), size(B), size(C) ];

... but I can't see any clean way of doing the recovery.

k=0;
U = reshape( vec(k+1:k+Ay*Ax), Ay, Ax);  k = k+Ay*Ax;
V = reshape( vec(k+1:k+By*Bx), By, Bx);  k = k+By*Bx;
W = reshape( vec(k+1:k+Cy*Cx), Cy, Cx);  k = k+Cy*Cx;

eeeeeyYUCK! Surely there has to be something better than this?


EDIT: In response to CST-link's question, @CST-Link, I actually have 7 objects so I don't need to be overly generic. However I'm actually dealing with the following structure:

A = ...; B = ...; C = ...; % only 7 mats
vec = pack(A,B,C);
ret = f( vec, g );
A_, B_, C_ = unpack(ret);

function ret = g( vec )
    U, V, W = unpack(vec);
    % fiddle U V W
    ret = pack(U,V,W);
end

... and f will invoke g(vec).

In order to perform the inner unpack, I would need to feed 7 target dimensions, so I guess I'm going to have to send that data in as a separate param:

A = ...; B = ...; C = ...; % only 7 mats
vec = pack(A,B,C);  sizes = getsizes(A,B,C);
ret = f( vec, g, sizes );
A_, B_, C_ = unpack(ret);

function ret = g( vec, sizes )
    U, V, W = unpack(vec, sizes);
    % fiddle U V W
    ret = pack(U,V,W);
end

... although the unpack function can still access A, B, C, so actually it would be tidier not to mess around with that extra sizes variable.

P i
  • 29,020
  • 36
  • 159
  • 267

1 Answers1

1

I'm not sure if this answers your question (i.e. if you consider this as clean), but here is a solution for 3 matrices:

A = randi(10,3,1);
B = randi(10,1,4);
C = randi(10,5,1);
vec = [ A(:).', B(:).', C(:).' ];
sizes =  [size(A).', size(B).', size(C).' ];

U = zeros(sizes(:,1).');
V = zeros(sizes(:,2).');
W = zeros(sizes(:,3).');
L = prod(sizes);
U(:) = vec(1:L(1));
V(:) = vec(L(1)+(1:L(2));
W(:) = vec(sum(L(1:2))+(1:L(3)));

it could be extended to a general solution quite easily, but the input and output vectors should than be stored in a cell array:

function PackUnpack
A = randi(10,3,2);
B = randi(10,1,4);
C = randi(10,5,3);
[vec,sizes] = pack({A,B,C});
ret = unpack(vec,sizes);
end

function [vec,sizes] = pack(mats)
sizes = zeros(2,numel(mats));
% build the size vector:
for k = 1:numel(mats)
    sizes(:,k) = size(mats{k}).';
end
L = prod(sizes);
vec = zeros(1,sum(L));
pos = cumsum([0 L]);
% flattening all matrices to one vector
for k = 1:numel(mats)
    vec((pos(k)+1):pos(k+1)) =  mats{k}(:).';
end
end

function cell_of_mat = unpack(vec,sizes)
cell_of_mat = cell(size(sizes,2),1);
sz = cumsum([0 prod(sizes)]);
% initialize all matrices to correct size and fill with values
for k = 1:numel(cell_of_mat)
    cell_of_mat{k} = zeros(sizes(:,k).');
    cell_of_mat{k}(:) = vec((sz(k)+1):sz(k+1));
end
end
EBH
  • 10,350
  • 3
  • 34
  • 59
  • @p-i Have a look at my edit for the general case. I prefer `for` loops on the cryptic notation of `arrayfun`, and they are also faster. – EBH Oct 06 '16 at 08:04
  • Thanks, nice code! It looks as though I can just use `'` not `.'`. Note to others that I could then do `[P, Q R] = ret{:};` to get out the actual matrices as separate subjects. I'm surprised you say `for` loops perform better than `arrayfun` -- I've read elsewhere that explicit looping is usually to be avoided wherever possible. – P i Oct 06 '16 at 10:00
  • 1
    @Pi It's a [better practice](http://stackoverflow.com/a/25150319/2627163) to use `.'`, and `arrayfun` is just a [fancy loop](http://stackoverflow.com/a/12526940/2627163), it's always slower then a simple unnested `for`. – EBH Oct 06 '16 at 10:53