faster sparse matric indexing in matlab - matlab

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

Related

How can I avoid this for-loop in spite of every element having to be checked individually?

Using Matlab R2019a, is there any way to avoid the for-loop in the following code in spite of the dimensions containing different element so that each element has to be checked? M is a vector with indices, and Inpts.payout is a 5D array with numerical data.
for m = 1:length(M)-1
for power = 1:noScenarios
for production = 1:noScenarios
for inflation = 1:noScenarios
for interest = 1:noScenarios
if Inpts.payout(M(m),power,production,inflation,interest)<0
Inpts.payout(M(m+1),power,production,inflation,interest)=...
Inpts.payout(M(m+1),power,production,inflation,interest)...
+Inpts.payout(M(m),power,production,inflation,interest);
Inpts.payout(M(m),power,production,inflation,interest)=0;
end
end
end
end
end
end
It is quite simple to remove the inner 4 loops. This will be more efficient unless you have a huge matrix Inpts.payout, as a new indexing matrix must be generated.
The following code extracts the two relevant 'planes' from the input data, does the logic on them, then writes them back:
for m = 1:length(M)-1
payout_m = Inpts.payout(M(m),:,:,:,:);
payout_m1 = Inpts.payout(M(m+1),:,:,:,:);
indx = payout_m < 0;
payout_m1(indx) = payout_m1(indx) + payout_m(indx);
payout_m(indx) = 0;
Inpts.payout(M(m),:,:,:,:) = payout_m;
Inpts.payout(M(m+1),:,:,:,:) = payout_m1;
end
It is possible to avoid extracting the 'planes' and writing them back by working directly with the input data matrix. However, this yields more complex code.
However, we can easily avoid some indexing operations this way:
payout_m = Inpts.payout(M(1),:,:,:,:);
for m = 1:length(M)-1
payout_m1 = Inpts.payout(M(m+1),:,:,:,:);
indx = payout_m < 0;
payout_m1(indx) = payout_m1(indx) + payout_m(indx);
payout_m(indx) = 0;
Inpts.payout(M(m),:,:,:,:) = payout_m;
payout_m = payout_m1;
end
Inpts.payout(M(m+1),:,:,:,:) = payout_m1;
It seems like there is not a way to avoid this. I am assuming that each for lop independently changes a variable parameter used in the main calculation. Thus, it is required to have this many for loops. My only suggestion is to turn your nested loops into a function if you're concerned about appearance. Not sure if this will help run-time.

How can we create random numbers without using any function rand in matlab?

b=round(rand(1,20));
Instead of using the function rand, I would like to know how to create such series.
This is a very interesting question. Actually, the easiest way to go, in my opinion is to use a Linear-feedback Shift Register. You can find plenty of examples and implementations googling around (here is one coming from another SO question).
Here is a quick Matlab demo based on this code:
b = lfsr(20)
function r = lfsr(size)
persistent state;
if (isempty(state))
state = uint32(1);
end
if (nargin < 1)
size = 1;
end
r = zeros(size,1);
for i = 1:size
r(i) = bitand(state,uint32(1));
if (bitand(state,uint32(1)))
state = bitxor(bitshift(state,-1),uint32(142));
else
state = bitshift(state,-1);
end
end
end

How to transfer excel formula to octave?

As you can see the image (excel file) I would like to use that formula in Octave to get the desired result. I also uploaded the octave codes picture and the workspace picture too. In workspace my result/values for storage variable should be the same values like that in excel (storage column). I have a doubt that in the code the last part using (if statement with i-1 is seems to be the error).
Can someone help me to figure it out? Let me know if any further clarifications required. Also I am posting my code below too:
BM_max = 1236;
virtual_feed_max = 64;
operation = dlmread ('2020Operation.csv');
BM = ones (size (operation, 1), 1);
for i=1:size(operation,1)
if operation(i,1)==1
BM(i,1)=BM_max;
else
BM(i,1)=0;
end
end
virtual_feed = ones(size(operation,1),1);
virtual_feed(:,1) = 64;
storage = ones(size(BM,1),1);
c = ones(size(BM,1),1);
for i=1:size(BM,1)
c=(BM(:,1)-virtual_feed(:,1));
end
for i=1:size(BM,1)
if ((i=1)&& c)<0
storage(:,1)=0;
elseif ((i=1)&& c)>0
storage(:,1)=c;
else
# Issue is below (Taking the value from subsequent row is the problem)
if (c+(storage(i-1,1)))<0
storage(:,1)=0;
elseif (c+(storage(i-1,1)))>0
storage(:,1)=(c+(storage(i-1,1)));
end
end
end
Workspace Excel
I think what you want is the following (as seen from your Excel screenshot)
BM_max = 1236;
virtual_feed_max = 64;
operation = [0; 1; 1; 1; 1; 1; 1; 1; 0; 0; 0; 0; 0];
BM = BM_max * operation;
virtual_feed = repmat (virtual_feed_max, size (operation));
storage = zeros (size (operation));
for i=2:numel (storage)
storage (i) = max (BM(i) - virtual_feed(i) + storage(i-1), 0);
endfor
storage
which outputs:
storage =
0
1172
2344
3516
4688
5860
7032
8204
8140
8076
8012
7948
7884
I leave the part of vectorization to make it faster for you. (hint: have a look at cumsum)
From this point on
for i=1:size(BM,1)
if ((i=1)&& c)<0
storage(:,1)=0;
elseif ((i=1)&& c)>0
storage(:,1)=c;
else
# Issue is below (Taking the value from subsequent row is the problem)
if (c+(storage(i-1,1)))<0
storage(:,1)=0;
elseif (c+(storage(i-1,1)))>0
storage(:,1)=(c+(storage(i-1,1)));
end
end
end
you are not changing a single value in storage but all the row/column, so each iteration, all the row/column is being changed instead of a single "cell".
You should use something like this:
storage(i,1) = 0;
BTW, a lot of those 'for' loops can be changed to vector operations. Example:
for i=1:size(BM,1)
c=(BM(:,1)-virtual_feed(:,1));
end
Can be changed for:
c = BM - virtual_feed;

Matlab function with for, if and else

I have a variable var0=rand(50,1).
I need to write a function that changes the first 5 lines to 0 and the rest to 1.
Ofcourse, I can simply do this like
var0=rand(50,1)
var0(1:5,1)=0
var0(6:end,1)=1
However I need to do this by using one for, one if and one else clause.
I tried many ways but can't get it working with for, it and else.Can someone please help with this fairly basic fuction?
Here's one implementation that meets the requirements:
stupidexercise = true;
topborder = 5;
var0 = rand(50,1);
if stupidexercise
for ii = 1:topborder
var0(ii, 1) = 0;
end
var0((topborder + 1):end, 1) = 1;
else
spy
end
As pointed out by others, this seems a silly assignment. Your approach is more efficient.
var0 = rand(50,1);
for ii = 1:50
if ii <= 5
var0(ii) = 0;
else
var0(ii) = 1;
end
end

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);