I had a question before but it was not as complete as this one! Actually, what I meant was that I have a nested if-for loop which I did not make it very clear before.
So, I have a very long code which is full of the following "if"s and matlab editor gives me a suggestion as follow:
this sparse indexing expression is likely to be slow
Is there any way by which I can make the code faster and do the matlab's suggestion? (The code may not run, because I just picked a few lines and tried to show the issue)
In my previous question, I did not explain that I need to use the i,j as index, so the answer was not convincing. But, as you can see here, I need to use the i and j as index which make the problem a little different from the previous post.
template = rand(200,200);
grid = rand(200,200);
T = size(template);
rws = size(grid,1);
cols = size(grid,2);
ind = "it is a matrix";
A = sparse(rws*cols,rws*cols);
T = sparse(rws*cols,2);
border_grid = 0;
border_template = 0;
template_comp = 0;
grid_comp = 0;
for i = 1:cols
for j = 1:rws
if(ind(j,i)==255)
Asr=grid(j,i,1);
Bsr=template(((j-posy)+1),((i-posx)+1),1);
Snorm= ((Asr-Bsr)^2)^(1/2);
if (( (j+1) > 0) && ((j+1) <= rws))
if ( ind(j+1,i)==0)
T((i-1)*rws+j,1)=100000;
border_grid=border_grid+1;
end
if ( ind(j+1,i)==128)
border_template=border_template+1;
T((i-1)*rws+j,2)=100000;
end
if( (ind(j+1,i)==255))
Atr=grid(j+1,i,1);
Btr=template(((j+1)-posy)+1,(i-posx)+1,1);
Tnorm= ((Atr-Btr)^2)^(1/2);
A((i-1)*rws+j,(i-1)*rws+(j+1))=Snorm+Tnorm;
end
end
end;
**+ some other similar if-loops**
end
end
I am relatively new to MATLAB and I am quite stuck in a specific problem.
I have an equation that I am trying to solve using a while loop. It works by guessing a certain parameter e_0 and filling it into the equation, until it converges. An example is found below, where the initial guessing value equals 100:
clear all
i=1;
e_0=100
e_1= e_0 + log(0.6) - log(exp(e_0)/(exp(e_0)+1))
while( i < 1e10 & abs((e_1 - e_0)) > 1e-12),
i = i + 1;
e_0=e_1;
e_1= e_0+log(0.6)-log(exp(e_0)/(exp(e_0)+1))
end
i
Now I would like the exact same procedure but then for multiple values of e_0 at the same time, e.g. 101, 102, 103 and so on, and count how many more iterations those will take. I reckon that I therefore need to put a for-loop for that. I thought something like this:
clear all
i=1;
for e_0 = 100:105
e_1= e_0+log(0.6)-log(exp(e_0)/(exp(e_0)+1))
while( i < 1e10 & abs((e_1 - e_0)) > 1e-12),
i = i + 1;
e_0=e_1;
e_1= e_0+log(0.6)-log(exp(e_0)/(exp(e_0)+1))
end
end
i
However, now all the iterations from the different guessing values are shown underneath each other, and I get a total of 1519 iterations. How can I for example store the number of iterations needed for every initial guessing value underneath each other into a variable?
I hope it is clear enough... Thank you!
How about this:
i = 0;
offset = 99;
for n = 1:6
e_0 = n + offset;
e_1 = e_0+log(0.6)-log(exp(e_0)/(exp(e_0)+1))
while( i < 1e10 & abs((e_1 - e_0)) > 1e-12),
i = i + 1;
This part needs to change to prevent e_0 to be redefined inside the loop:
e_1= e_1+log(0.6)-log(exp(e_1)/(exp(e_1)+1))
end
iterations(n)=i;
end
Note: it is not recommended to use i as a loop increment, since it redefines i used in complex numbers.
I have a code with two for loops. The code is working properly. The problem is that at the end I would like to get a variable megafinal with the results for all the years. The original varaible A has 3M rows, so it gives me an error because the size of the megafinal changes with each loop iteration and matlab stops running the code. I guess it’s a problem of inefficiency. Does anyone know a way to get this final variable despite of the size?
y = 1997:2013;
for i=1:length(y)
A=b(cell2mat(b(:,1))==y(i),:);
%Obtain the absolute value of the difference
c= cellfun(#minus,A(:,3),A(:,4));
c=abs(c);
c= num2cell(c);
A(:,end+1) = c;
%Delete rows based on a condition
d = (abs(cell2mat(A(:,8)) - cell2mat(A(:,7))));
[~, ind1] = sort(d);
e= A(ind1(end:-1:1),:);
[~, ind2,~] = unique(strcat(e(:,2),e(:, 6)));
X= e(ind2,:);
(…)
for j = 2:length(X)
if strcmp(X(j,2),X(j-1,2)) == 0
lin2 = j-1;
%Sort
X(lin1:lin2,:) = sortrows(X(lin1:lin2,:),13);
%Rank
[~,~,f]=unique([X{lin1:lin2,13}].');
g=accumarray(f,(1:numel(f))',[],#mean);
X(lin1:lin2,14)=num2cell(g(f));
%Score
out1 = 100 - ((cell2mat(X(lin1:lin2,14))-1) ./ size(X(lin1:lin2,:),1))*100;
X(lin1:lin2,15) = num2cell(out1);
lin1 = j;
end
end
%megafinal(i)=X
end
Make megafinal a cell array. This will account for the varying sizes of X at each iteration. As such, simply do this:
megafinal{i} = X;
To access a cell element, you just have to do megafinal{num}, where num is any index you want.
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
I'm having a kind of trouble since I'm new the concept Image Analysis and the tool Matlab.
What I have in my mind does not work well as lines of codes.
I'm trying to dilation function for binary images. It has to widen the given binary images.
This is my main page:
I = imread('logo_XXXX.png');
binaryImage = im2bw(I, 0.4);
s = ones(3,3,'int8');
i = dilate(binaryImage,s);
figure, imshow(i);
This is dilate.m function:
function [i] = dilate(I,s)
[Irows,Icols] = size(I);
i=I;
Itemp = I;
for row=1:Irows
for col=1:Icols
x = intersectAt(Itemp,s,row,col);
if x == 1
i(row,col)=1;
else
i(row,col)=0;
end
end
end
And this is istersectAt.m function:
function [i] = intersectAt(I,s,row,col)
[Srows,Scols] = size(s);
[Irows,Icols] = size(I);
i=0;
rowx = row - int8(Srows/2);
colx = col - int8(Scols/2);
for r=1:Srows
for c=1:Scols
if rowx+r <= 0 || rowx+r > Irows || colx+c <= 0 || colx+c > Icols
continue;
elseif I(rowx+r,colx+c) == 1 && s(r,c)==1
i = 1;
end
end
end
These codes must be widen this image:
however, in some point it doesn't work properly s.t:
If you help me fix my code I would be appriciated. If you want to know about dilation you can follow this url: http://www.mathworks.com/help/toolbox/images/f18-12508.html
Matlab has this function in its library but i need to implement my own function.
You should avoid loops as much as possible in matlab.
If you need to write your own function just do:
s=ones(3);
i=(conv2(double(binaryImage),s,'same')>0)
From your example:
I can obtain:
I will give a hint then. Ask yourself what int8() exactly does for a number larger then 127. Incidentally the column index number after which your algorithm start behaving weird.
Edit to clarify
If you subtract a int8 type number from another one, a double in this case, Matlab will automatically cast to int8. For example:
test = double(140) - int8(3)
Gives a 127.
I assume imdilate is implemented with conv2, but your code would be more readable if you used this:
b = imdilate(bwImage,ones(3));