Avoiding for-loops in matrix operations with cell elements - matlab

The dimensions of this problem are: model.nlf = 4. Each {r} of Kuu or KuuGamma are 500x500 matrices of data.
How to suppress the for-loop? my intuition goes toward using cellfun with a function for logdet.
logDetKuu = 0;
for r=1:model.nlf,
if isfield(model, 'gamma') && ~isempty(model.gamma)
[model.Kuuinv{r}, model.sqrtKuu{r}] = pdinv(model.KuuGamma{r});
model.logDetKuu{r} = logdet(model.KuuGamma{r}, model.sqrtKuu{r});
else
[model.Kuuinv{r}, model.sqrtKuu{r}] = pdinv(model.Kuu{r});
model.logDetKuu{r} = logdet(model.Kuu{r}, model.sqrtKuu{r});
end
logDetKuu = logDetKuu + model.logDetKuu{r};
end
Grateful for pointers. Thanks
Follow up question: Can the following type of for-loops on cell elements be vectorized?
nlf = 4; nout = 16; each KuuinvKuy{1,1} are 150x650
for k =1: model.nout,
for r =1: model.nlf,
model.KuuinvKuy{r,k} = model.Kuuinv{r}*model.Kyu{k,r}';
end
end

If all your matrices are so large, and you execute your for-loop only 4 times, then there is no reason to remove the for-loops, since it will not lead to any speedup. My only observation is that the condition of the if seems to be independent of the loop, so it is cleaner to move that if before the loop. Something like this:
if isfield(model, 'gamma') && ~isempty(model.gamma)
myKuu = model.KuuGamma;
else
myKuu = model.Kuu;
end
logDetKuu = 0;
for r=1:model.nlf,
[model.Kuuinv{r}, model.sqrtKuu{r}] = pdinv(myKuu{r});
model.logDetKuu{r} = logdet(myKuu{r}, model.sqrtKuu{r});
logDetKuu = logDetKuu + model.logDetKuu{r};
end

Related

Parallelizing MATLAB code

Hello I want to use parallelize my MATLAB code to run High computing server. It is code to make image database for Deep learning. To parallelize the code I found the I have to for parfor loop. But I used that with the first loop or with the second loop it shows me error parfor cannot be run due to the variable imdb and image_counter. Anyone please help me to change the code to work with parfor
for i = 1:length(cur_images)
X = sprintf('image Numb: %d ',i);
disp(X)
cur_image = load(cur_images{i,:});
cur_image=(cur_image.Image.crop);
%----------------------------------------------
cur_image = imresize(cur_image, image_size);
if(rgb < 1)
imdb.images.data(:,:,1,image_counter) = cur_image;
else
imdb.images.data(:,:,1,image_counter) = cur_image(:,:,1);
imdb.images.data(:,:,2,image_counter) = cur_image(:,:,2);
imdb.images.data(:,:,3,image_counter) = cur_image(:,:,3);
imdb.images.data(:,:,4,image_counter) = cur_image(:,:,4);
imdb.images.data(:,:,5,image_counter) = cur_image(:,:,5);
imdb.images.data(:,:,6,image_counter) = cur_image(:,:,6);
imdb.images.data(:,:,7,image_counter) = cur_image(:,:,7);
imdb.images.data(:,:,8,image_counter) = cur_image(:,:,8);
imdb.images.data(:,:,9,image_counter) = cur_image(:,:,9);
imdb.images.data(:,:,10,image_counter) = cur_image(:,:,10);
end
imdb.images.set( 1,image_counter) = set;
image_counter = image_counter + 1;
end
The main problem here is that you can't assign to fields of a structure inside parfor in the way that you're trying to do. Also, your outputs need to be indexed by the loop variable to qualify as "sliced" - i.e. don't use image_counter. Putting this together, you need something more like:
% Make a numeric array to store the output.
data_out = zeros([image_size, 10, length(cur_images)]);
parfor i = 1:length(cur_images)
cur_image = load(cur_images{i, :});
cur_image=(cur_image.Image.crop);
cur_image = imresize(cur_image, image_size);
% Now, assign into 'data_out'. A little care needed
% here.
if rgb < 1
data_tmp = zeros([image_size, 10]);
data_tmp(:, :, 1) = cur_image;
else
data_tmp = cur_image;
end
data_out(:, :, :, i) = data_tmp;
end
imdb.images.data = data_out;

Is there a way to optimize or maybe even vectorize this? (MATLAB)

I have an if statement within two loops, it runs too slow and I think it can be optimized. NF_zeta is a 2D logical array.
for k = 2:Nx
for l = 2:Ny
if NF_zeta(l,k)
z2(l,k) = z1(l,k) - optVar2*(U2(l,k) - U2(l,k-1) + V2(l,k) - V2(l-1,k));
end
end
end
Here are the results of a profiler
http://i.imgur.com/oMropeL.png
I tried with single loop in which the conditional statement was taken care of. Something similar to what is done for one loop for [1 4 5], I wrote
for idx = NF_zeta_v
z2(idx(1),idx(2)) = z1(idx(1),idx(2)) - optVar2*(U2(idx(1),idx(2)) - U2(idx(1),idx(2)-1) + V2(idx(1),idx(2)) - V2(idx(1)-1,idx(2)));
end
where NF_zeta_v is created in advance like this
c_z = 1;
for l = 1:Ny
for k = 1:Nx
if NF_zeta(l,k)
NF_zeta_v(:,c_z) = [l;k];
c_z = c_z + 1;
end
end
end
It took almost twice as long. The results of a profiler http://i.imgur.com/OegeEOC.png
What else can I try, any suggestions?
Here's one vectorized solution using diff -
diffs = diff(U2(2:end,:),[],2) + diff(V2(:,2:end),[],1);
allvals = z1(2:end,2:end) - optVar2*diffs;
z2(2:Ny,2:Nx) = NF_zeta(2:Ny,2:Nx).*allvals;
May be you want something like this if N_x and N_y are the size values:
Z2 = (z1-optVar2*(U2-circshift(U2, [0 1])+V2-circshift(V2, [1 0]))).*(double(NF_zeta));
Z2(1,:) = 0;
Z2(:,1) = 0;

Avoid for loop for setting the matrix element in Matlab

In a matrix, how does one set an adjacent and diagonal element to 1 if the values in these locations are the same avoiding a for loop?
An attempt made with for loop is given
[r,c] = size(mat1);
Sval = zeros(size(mat1));
for i = 1:r
for j = 1:c-1
if(mat1(i,j) == mat1(i,j+1))
Sval(i,j) = 1;
Sval(i,j+1) = 1;
else
Sval(i,j) = 0;
Sval(i,j+1) = 0;
end;
end;
end;
To receive the exact same output without the loops the code is the following. However it is not quite clear what you want to achieve with this code. Please elaborate further if this doesn't answer your question.
Sval = mat1(:,1:c-1) == mat1(:,2:c);
Sval(:,c) = Sval(:,c-1);
If I interpret your sentence right what you actually want is to shift/copy the equal values to the right as well. This could be achived by:
Sval = mat1(:,1:c-1) == mat1(:,2:c);
Sval(:,c) = zeros(r,1);
Sval(:,2:c) = Sval(:,1:c-1) | Sval(:,2:c);

Fill matrix with function values in Matlab

I've got 3 functions, oe1(n), oe2(n) and oe3(n).
I want to create a matrix representing the function values.
The structure of the matrix should be like this:
A = [oe1(0) oe2(0) oe3(0); oe1(1) oe2(1) od3(1); ...... ; oe1(N-1), oe2(N-1), oe3(N-1)];
I've tried filling it with a for loop, but it does not work.
Is there a standard Matlab operation for this? I really can't figure out how to do it.
Anders.
oe1(n1) = sin(2*pi*F*n1+phi)
oe2(n1) = ones(length(n1),1);
oe3(n1) = n1*Ts
pol = (oe2)'
vector_x = [a; b; c];
vector_veardier = [oe1(n1), 1, oe3(n1)]
xi = 1:N-1;
for i = 2:N-1;
for j = 1:3
vector_veardier(i, j) = oe1(j);
end
end
Do your functions accept vectors? If so you can use:
A = [oe1((1:N)'), oe2((1:N)'), oe3((1:N)')];
but otherwise you might have to use arrayfun:
A = [arrayfun(#oe1, (1:N)'), arrayfun(#oe2, (1:N)'), arrayfun(#oe3, (1:N)')];
Note that in your provided code you have not defined oeN as functions, but as some kind of array with a value inserted at position n1.
One way to do it with a for loop would however be:
A = zeros(N,3);
for i = 1:N,
A(i,:) = [oe1(i), oe2(i) oe3(i)];
end

How to improve execution time of the following Matlab code

Please help me to improve the following Matlab code to improve execution time.
Actually I want to make a random matrix (size [8,12,10]), and on every row, only have integer values between 1 and 12. I want the random matrix to have the sum of elements which has value (1,2,3,4) per column to equal 2.
The following code will make things more clear, but it is very slow.
Can anyone give me a suggestion??
clc
clear all
jum_kel=8
jum_bag=12
uk_pop=10
for ii=1:uk_pop;
for a=1:jum_kel
krom(a,:,ii)=randperm(jum_bag); %batasan tidak boleh satu kelompok melakukan lebih dari satu aktivitas dalam satu waktu
end
end
for ii=1:uk_pop;
gab1(:,:,ii) = sum(krom(:,:,ii)==1)
gab2(:,:,ii) = sum(krom(:,:,ii)==2)
gab3(:,:,ii) = sum(krom(:,:,ii)==3)
gab4(:,:,ii) = sum(krom(:,:,ii)==4)
end
for jj=1:uk_pop;
gabh1(:,:,jj)=numel(find(gab1(:,:,jj)~=2& gab1(:,:,jj)~=0))
gabh2(:,:,jj)=numel(find(gab2(:,:,jj)~=2& gab2(:,:,jj)~=0))
gabh3(:,:,jj)=numel(find(gab3(:,:,jj)~=2& gab3(:,:,jj)~=0))
gabh4(:,:,jj)=numel(find(gab4(:,:,jj)~=2& gab4(:,:,jj)~=0))
end
for ii=1:uk_pop;
tot(:,:,ii)=gabh1(:,:,ii)+gabh2(:,:,ii)+gabh3(:,:,ii)+gabh4(:,:,ii)
end
for ii=1:uk_pop;
while tot(:,:,ii)~=0;
for a=1:jum_kel
krom(a,:,ii)=randperm(jum_bag); %batasan tidak boleh satu kelompok melakukan lebih dari satu aktivitas dalam satu waktu
end
gabb1 = sum(krom(:,:,ii)==1)
gabb2 = sum(krom(:,:,ii)==2)
gabb3 = sum(krom(:,:,ii)==3)
gabb4 = sum(krom(:,:,ii)==4)
gabbh1=numel(find(gabb1~=2& gabb1~=0));
gabbh2=numel(find(gabb2~=2& gabb2~=0));
gabbh3=numel(find(gabb3~=2& gabb3~=0));
gabbh4=numel(find(gabb4~=2& gabb4~=0));
tot(:,:,ii)=gabbh1+gabbh2+gabbh3+gabbh4;
end
end
Some general suggestions:
Name variables in English. Give a short explanation if it is not immediately clear,
what they are indented for. What is jum_bag for example? For me uk_pop is music style.
Write comments in English, even if you develop source code only for yourself.
If you ever have to share your code with a foreigner, you will spend a lot of time
explaining or re-translating. I would like to know for example, what
%batasan tidak boleh means. Probably, you describe here that this is only a quick
hack but that someone should really check this again, before going into production.
Specific to your code:
Its really easy to confuse gab1 with gabh1 or gabb1.
For me, krom is too similar to the built-in function kron. In fact, I first
thought that you are computing lots of tensor products.
gab1 .. gab4 are probably best combined into an array or into a cell, e.g. you
could use
gab = cell(1, 4);
for ii = ...
gab{1}(:,:,ii) = sum(krom(:,:,ii)==1);
gab{2}(:,:,ii) = sum(krom(:,:,ii)==2);
gab{3}(:,:,ii) = sum(krom(:,:,ii)==3);
gab{4}(:,:,ii) = sum(krom(:,:,ii)==4);
end
The advantage is that you can re-write the comparsisons with another loop.
It also helps when computing gabh1, gabb1 and tot later on.
If you further introduce a variable like highestNumberToCompare, you only have to
make one change, when you certainly find out that its important to check, if the
elements are equal to 5 and 6, too.
Add a semicolon at the end of every command. Having too much output is annoying and
also slow.
The numel(find(gabb1 ~= 2 & gabb1 ~= 0)) is better expressed as
sum(gabb1(:) ~= 2 & gabb1(:) ~= 0). A find is not needed because you do not care
about the indices but only about the number of indices, which is equal to the number
of true's.
And of course: This code
for ii=1:uk_pop
gab1(:,:,ii) = sum(krom(:,:,ii)==1)
end
is really, really slow. In every iteration, you increase the size of the gab1
array, which means that you have to i) allocate more memory, ii) copy the old matrix
and iii) write the new row. This is much faster, if you set the size of the
gab1 array in front of the loop:
gab1 = zeros(... final size ...);
for ii=1:uk_pop
gab1(:,:,ii) = sum(krom(:,:,ii)==1)
end
Probably, you should also re-think the size and shape of gab1. I don't think, you
need a 3D array here, because sum() already reduces one dimension (if krom is
3D the output of sum() is at most 2D).
Probably, you can skip the loop at all and use a simple sum(krom==1, 3) instead.
However, in every case you should be really aware of the size and shape of your
results.
Edit inspired by Rody Oldenhuis:
As Rody pointed out, the 'problem' with your code is that its highly unlikely (though
not impossible) that you create a matrix which fulfills your constraints by assigning
the numbers randomly. The code below creates a matrix temp with the following characteristics:
The numbers 1 .. maxNumber appear either twice per column or not at all.
All rows are a random permutation of the numbers 1 .. B, where B is equal to
the length of a row (i.e. the number of columns).
Finally, the temp matrix is used to fill a 3D array called result. I hope, you can adapt it to your needs.
clear all;
A = 8; B = 12; C = 10;
% The numbers [1 .. maxNumber] have to appear exactly twice in a
% column or not at all.
maxNumber = 4;
result = zeros(A, B, C);
for ii = 1 : C
temp = zeros(A, B);
for number = 1 : maxNumber
forbiddenRows = zeros(1, A);
forbiddenColumns = zeros(1, A/2);
for count = 1 : A/2
illegalIndices = true;
while illegalIndices
illegalIndices = false;
% Draw a column which has not been used for this number.
randomColumn = randi(B);
while any(ismember(forbiddenColumns, randomColumn))
randomColumn = randi(B);
end
% Draw two rows which have not been used for this number.
randomRows = randi(A, 1, 2);
while randomRows(1) == randomRows(2) ...
|| any(ismember(forbiddenRows, randomRows))
randomRows = randi(A, 1, 2);
end
% Make sure not to overwrite previous non-zeros.
if any(temp(randomRows, randomColumn))
illegalIndices = true;
continue;
end
end
% Mark the rows and column as forbidden for this number.
forbiddenColumns(count) = randomColumn;
forbiddenRows((count - 1) * 2 + (1:2)) = randomRows;
temp(randomRows, randomColumn) = number;
end
end
% Now every row contains the numbers [1 .. maxNumber] by
% construction. Fill the zeros with a permutation of the
% interval [maxNumber + 1 .. B].
for count = 1 : A
mask = temp(count, :) == 0;
temp(count, mask) = maxNumber + randperm(B - maxNumber);
end
% Store this page.
result(:,:,ii) = temp;
end
OK, the code below will improve the timing significantly. It's not perfect yet, it can all be optimized a lot further.
But, before I do so: I think what you want is fundamentally impossible.
So you want
all rows contain the numbers 1 through 12, in a random permutation
any value between 1 and 4 must be present either twice or not at all in any column
I have a hunch this is impossible (that's why your code never completes), but let me think about this a bit more.
Anyway, my 5-minute-and-obvious-improvements-only-version:
clc
clear all
jum_kel = 8;
jum_bag = 12;
uk_pop = 10;
A = jum_kel; % renamed to make language independent
B = jum_bag; % and a lot shorter for readability
C = uk_pop;
krom = zeros(A, B, C);
for ii = 1:C;
for a = 1:A
krom(a,:,ii) = randperm(B);
end
end
gab1 = sum(krom == 1);
gab2 = sum(krom == 2);
gab3 = sum(krom == 3);
gab4 = sum(krom == 4);
gabh1 = sum( gab1 ~= 2 & gab1 ~= 0 );
gabh2 = sum( gab2 ~= 2 & gab2 ~= 0 );
gabh3 = sum( gab3 ~= 2 & gab3 ~= 0 );
gabh4 = sum( gab4 ~= 2 & gab4 ~= 0 );
tot = gabh1+gabh2+gabh3+gabh4;
for ii = 1:C
ii
while tot(:,:,ii) ~= 0
for a = 1:A
krom(a,:,ii) = randperm(B);
end
gabb1 = sum(krom(:,:,ii) == 1);
gabb2 = sum(krom(:,:,ii) == 2);
gabb3 = sum(krom(:,:,ii) == 3);
gabb4 = sum(krom(:,:,ii) == 4);
gabbh1 = sum(gabb1 ~= 2 & gabb1 ~= 0)
gabbh2 = sum(gabb2 ~= 2 & gabb2 ~= 0);
gabbh3 = sum(gabb3 ~= 2 & gabb3 ~= 0);
gabbh4 = sum(gabb4 ~= 2 & gabb4 ~= 0);
tot(:,:,ii) = gabbh1+gabbh2+gabbh3+gabbh4;
end
end