Why does matlab warn to preallocate a variable which is getting reset every loop? - matlab

There is a cell variable in my program which Matlab warns to preallocate it. The simple form of code is sth like this:
for i = 1:2
a = [];
a = [a,{'abc'}];
end
First I want to know why a should be preallocated, since it's getting reset in each loop. Second I don't know how to preallocate it. When I try to do so, Matlab gives me another warning, saying "The variable appears to be preallocated, but preallocation is not recommended here".
I use this code before the loop:
a = cell(1,2);
To be more specific:
for i = 1:2
a = [];
if condition1
a = {'abc'};
end
if condition2
a = [a,{'def'}];
end
b = [{'string'},a];
end
I want b to be a 1x1 cell array if the conditions are not true, so I need to reset a to an empty var in each loop.
Update:
I found a way, hinted by Lee's answer, but still doesn't know why. Using a = [a(:),{'def'}]; instead of a = [a,{'def'}]; solved the warning.

You made a a new variable, thus the former a = cell(1,2) was never used, which made matlab raised the warning.
You can use sth like
a = cell(1,2);
for ii = 1:2
a{ii} = 'abc';
end
or if you really want to change the size of a,
for ii = 1:2
a = {'a1'};
a = [a(:); {'abc'}];
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.

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;

Continue ‘for’ loop with the existing variables in Matlab

I have a Matlab script including a for loop which loos like the following:
for k = 1:10
c = myfun(k,a,b);
result{k} = c;
end
Right now, the problem is that during the for loop, sometimes myfun() may have errors and stop. After fixing the error in myfun(), how can I continue to run with the existing value of variables? The reason is that myfun() will take a very long time to get the result and the previous results are right.
For example, if a error happens when k == 4, then I save all the variables in the current workspace. I set a breakpoint at c = myfun(k,a,b); and restore the saved variables, but I find that in the next loop, k will be 2 instead of 5 as I want. Matlab is not allowed to modify the value of k during the for loop I think. I have tested this for a few times.
How can I continue the for loop with some existing data?
You cannot change your for loop iterator programmatically inside of the loop.
For example:
for ii = 1:3
disp(ii)
ii = 3;
end
Prints:
1
2
3
If you're going to be modifying code based on errors received, dbstop if error is not going to be beneficial because it will not reflect changes in your code until the debugger is exited and your code executed again (unless you execute manually in the debugger). If you're not modifying code you could potentially use a try/except clause to catch fixable issues.
If you're loading data for a later index and then restarting, you can change where your for loop begins, or use a while loop (if appropriate).
For example:
% Load data here
for ii = 3:3
disp(ii)
end
Prints 3.
Where the while interpretation would be:
% Load data here
ii = 3
while ii <= 3
disp(ii)
ii = ii + 1;
end
For the same result.
On solution can be first catch the exception likes the following and pass from them:
bug = [];
for k = 1:10
try
c = myfun(k,a,b);
result{k} = c;
catch
warning('some bug for the following values:');
display([k a b]);
bug = [bug; k a b];
result{k} = NaN;
end
end
Then iterate over bug to compute missing information after debugging. This solution works when your algorithm is not dependent on the previous value of the result (or is not recursive).

Looping a Function in Matlab

total newbie here. I'm having problems looping a function that I've created. I'm having some problems copying the code over but I'll give a general idea of it:
function[X]=Test(A,B,C,D)
other parts of the code
.
.
.
X = linsolve(K,L)
end
where K,L are other matrices I derived from the 4 variables A,B,C,D
The problem is whenever I execute the function Test(1,2,3,4), I can only get one answer out. I'm trying to loop this process for one variable, keep the other 3 variables constant.
For example, I want to get answers for A = 1:10, while B = 2, C = 3, D = 4
I've tried the following method and they did not work:
Function[X] = Test(A,B,C,D)
for A = 1:10
other parts of the code...
X=linsolve(K,L)
end
Whenever I keyed in the command Test(1,2,3,4), it only gave me the output of Test(10,2,3,4)
Then I read somewhere that you have to call the function from somewhere else, so I edited the Test function to be Function[X] = Test(B,C,D) and left A out where it can be assigned in another script eg:
global A
for A = 1:10
Test(A,2,3,4)
end
But this gives an error as well, as Test function requires A to be defined. As such I'm a little lost and can't seem to find any information on how can this be done. Would appreciate all the help I can get.
Cheers guys
I think this is what you're looking for:
A=1:10; B=2; C=3; D=4;
%Do pre-allocation for X according to the dimensions of your output
for iter = 1:length(A)
X(:,:,iter)= Test(A(iter),B,C,D);
end
X
where
function [X]=Test(A,B,C,D)
%other parts of the code
X = linsolve(K,L)
end
Try this:
function X = Test(A,B,C,D)
% allocate output (it is faster than changing the size in every loop)
X = {};
% loop for each position in A
for i = 1:numel(A);
%in the other parts you have to use A(i) instead of just A
... other parts of code
%overwrite the value in X at position i
X{i} = linsolve(K,L);
end
end
and run it with Test(1:10,2,3,4)
To answer what went wrong before:
When you loop with 'for A=1:10' you overwrite the A that was passed to the function (so the function will ignore the A that you passed it) and in each loop you overwrite the X calculated in the previous loop (that is why you can only see the answer for A=10).
The second try should work if you have created a file named Test.m with the function X = (A,B,C,D) as the first code in the file. Although the global assignment is unnecessary. In fact I would strongly recommend you not to use global variables as it gets very messy very fast.

Problem with a variable not changing value in MATLAB

So I have one problem with my code, which is that one variable is not working as it's supposed to do. Here are the codes I'm using:
format long
f = inline('-x.^2');
for i = 0:10
[I(i+1) h(i+1) tid(i+1)] = trapets(f,0,1,2^i);
end
for i = 0:10
trunk(i+1) = I(i+1) - log(2);
end
hold on
grid on
plot(log(h),log(trunk),'r+')
t = -7:0;
c = polyfit(log(h),log(trunk),1);
yy = polyval(c,t);
plot(t,yy)
grid off
hold off
koefficienter = real(c)
and also this:
function [ I,h,tid ] = trapets(f,a,b,n )
h=(b-a)/n;
tic;
I=(f(a)+f(b));
for k=2:2:n-2
I = I+2*f(a+k*h);
end
for k = 1:2:n-1
I = I + 4*f(a+k*h);
end
I = I * h/3;
tid = toc;
end
So the problem here is that the variable I is not changing value. It gets 11 values when I run the first code (I don't run the last code I wrote, it's only used by the first one), but the values are all the same. I don't know if the problem is that the variable n, which I use in the the second code, never change value, although I'm trying to do that with the "2^i" part in "trapets(f,0,1,2^i)". If the case is that n never change value, is there a solution to do that?
And if the problem is not the variable n, why doesn't the variable I change value in the code?
After running your program I found out the I always equals -1/h after the for loops, which makes I = I * h/3; always give you the same result.