How to sample single values from field in *non-scalar structure array*?
3 visualizzazioni (ultimi 30 giorni)
Mostra commenti meno recenti
Manuel A. Diaz
il 25 Lug 2023
Commentato: Manuel A. Diaz
il 26 Lug 2023
Hello Matlab experts,
I'm working on the optimization of some code following the Profiler's measurements.
Here, one main bottleneck is the sampling of an individual element on each of the fields contained within the struct array.
For context, let's consider that a non-scalar struct array with uniform mat sparse fields is built as
A = repmat(struct('mat',speye(3)),10,1);
for k = 1:10
A(k).mat = A(k).mat * k;
end
For the sake of simplicity, I'm interested in sampling each field at indexes (i,j) = (2,2) as
col = zeros(10,1);
for k = 1:10
col(k) = A(k).mat(2,2);
end
So that for the next step, I report each sampled point into a column vector.
Thus the expected output is:
>> col
col =
1
2
3
4
5
6
7
8
9
10
Question: is there a much better (hopefully faster) way to do this? (mainly getting rid of the for-loop)
Disclaimer: I have tried converting this struct array into flat array, [A.mat], or into an array of cells, {A.mat}, but I run into the trouble of the sparse nature of the fields (Get warnings with SPFUN). I'm sure there must be a clever way to do this with arrayfun() or cellfun() but the solution eludes me.
8 Commenti
Bruno Luong
il 26 Lug 2023
Modificato: Bruno Luong
il 26 Lug 2023
You might take a look at this FEX by @Matt J
Risposta accettata
Manuel A. Diaz
il 26 Lug 2023
7 Commenti
Bruno Luong
il 26 Lug 2023
Modificato: Bruno Luong
il 26 Lug 2023
The speed up depends on the size of mat. Less than 100, the speed up is real; beyond that the flatten runtime increases with the size where-as the for-loop time is constant, independent of the size of the matrix, as showed,in this test script.
matsize = 2.^(1:12);
ntest = length(matsize);
t1 = zeros(1, ntest);
t2 = zeros(1, ntest);
t3 = zeros(1, ntest);
for i = 1:ntest
A = repmat(struct('mat',speye(matsize(i))),10000,1);
for k = 1:numel(A)
A(k).mat = A(k).mat * k;
end
t1(i) = timeit(@() forloop(A), 1);
t2(i) = timeit(@() flatA(A), 1);
t3(i) = timeit(@() afun(A), 1);
end
close all
semilogx(matsize, t1)
hold on
semilogx(matsize, t2)
semilogx(matsize, t3)
xlabel('sizemat')
ylabel('time [s]')
legend('for loop', 'flat mat', 'arrayfun')
function col = forloop(A)
n = numel(A);
col = zeros(n,1);
for k = 1:n
col(k) = A(k).mat(2,2);
end
end
function col = afun(A)
col = arrayfun(@(s) full(s.mat(2,2)), A);
end
function col = flatA(A)
n = numel(A);
% Get Data sizes
m = size(A(1).mat,1); % because we have uniformly sized fields
% Compute
A_flat = [A.mat]; % Flatten the structure fields
col = transpose(A_flat(2,2 + 0:m:m*n));
end
Più risposte (1)
Bruno Luong
il 25 Lug 2023
Modificato: Bruno Luong
il 25 Lug 2023
Just shorter code, not necessary better.
A = repmat(struct('mat',speye(3)),10,1);
for k = 1:10
A(k).mat = A(k).mat * k;
end
col = arrayfun(@(s) full(s.mat(2,2)), A)
Vedere anche
Categorie
Scopri di più su Matrices and Arrays in Help Center e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


