This piece of code works as I want it to, but in the spirit of good MATLAB code, is there a way to vectorize this (previous is a k x 1 vector):
start = zeros(k,1);
for i = 2:length(previous)
if (previous(i-1) == -1)
start(previous(i))= start(previous(i))+1;
end
end
What, in general, is the intuitive way to go about vectorizing code in MATLAB?
Use the find command in MATLAB, which returns the index (i) for which a vector is TRUE. So:
% precache indices i where previous(i-1) == 1
idx = find(previous==-1)+1;
start(previous(idx)) = start(previous(idx))+1;
The reason I precache idx is in case that previous is a big vector and doing the find takes a while. Otherwise you could just do
start( find(previous==-1)+1 ) = start( find(previous==-1) ) + 1;
You can do this without find, for maximum performance:
I = [false; previous(1:end-1) == -1];
idx = previous(I);
start(idx) = start(idx) + 1;
This also avoids the risk that previous(end) == -1, which would cause an index out-of-range error in the alternative.
Note that this doesn't work the same as your original if idx contains duplicated indices.
I would do something like:
prev_is_minus1 = [false; previous(1:end-1)==-1]
start = accumarray(previous(prev_is_minus1), 1, k)
I believe this has the same effect as the code loop you posted.
Related
I am trying to write a MATLAB function that accepts non-integer, n, and then returns the factorial of it, n!. I am supposed to use a for loop. I tried with
"for n >= 0"
but this did not work. Is there a way how I can fix this?
I wrote this code over here but this doesn't give me the correct answer..
function fact = fac(n);
for fact = n
if n >=0
factorial(n)
disp(n)
elseif n < 0
disp('Cannot take negative integers')
break
end
end
Any kind of help will be highly appreciated.
You need to read the docs and I would highly recommend doing a basic tutorial. The docs state
for index = values
statements
end
So your first idea of for n >= 0 is completely wrong because a for doesn't allow for the >. That would be the way you would write a while loop.
Your next idea of for fact = n does fit the pattern of for index = values, however, your values is a single number, n, and so this loop will only have one single iteration which is obviously not what you want.
If you wanted to loop from 1 to n you need to create a vector, (i.e. the values from the docs) that contains all the numbers from 1 to n. In MATLAB you can do this easily like this: values = 1:n. Now you can call for fact = values and you will iterate all the way from 1 to n. However, it is very strange practice to use this intermediary variable values, I was just using it to illustrate what the docs are talking about. The correct standard syntax is
for fact = 1:n
Now, for a factorial (although technically you'll get the same thing), it is clearer to actually loop from n down to 1. So we can do that by declaring a step size of -1:
for fact = n:-1:1
So now we can find the factorial like so:
function output = fac(n)
output = n;
for iter = n-1:-1:2 %// note there is really no need to go to 1 since multiplying by 1 doesn't change the value. Also start at n-1 since we initialized output to be n already
output = output*iter;
end
end
Calling the builtin factorial function inside your own function really defeats the purpose of this exercise. Lastly I see that you have added a little error check to make sure you don't get negative numbers, that is good however the check should not be inside the loop!
function output = fac(n)
if n < 0
error('Input n must be greater than zero'); %// I use error rather than disp here as it gives clearer feedback to the user
else if n == 0
output = 1; %// by definition
else
output = n;
for iter = n-1:-1:2
output = output*iter;
end
end
end
I don't get the point, what you are trying to do with "for". What I think, what you want to do is:
function fact = fac(n);
if n >= 0
n = floor(n);
fact = factorial(n);
disp(fact)
elseif n < 0
disp('Cannot take negative integers')
return
end
end
Depending on your preferences you can replace floor(round towards minus infinity) by round(round towards nearest integer) or ceil(round towards plus infinity). Any round operation is necessary to ensure n is an integer.
I've run an experiment where a machine exerts a force on a bridge until it breaks. I need to cycle through my entire data set and calculate the toughness until I've hit the breaking point (fdValue1).
The toughness is calculated by summing up all the rectangles under my load vs. distance curve. (Basically the integral)
However, I have not been able to find a reasonable way of doing so and my current loop is an infinite loop and I'm not sure why.
%Initializing variables
bridge1Data = xlsread('Bridge1Data.xlsx', 'A2:C2971');
bridge2Data = xlsread('Bridge2Data.xlsx', 'A2:C1440');
bridge1Load = bridge1Data(:, 2);
bridge2Load = bridge2Data(:, 2);
bridge1Dist = bridge1Data(:, 3);
bridge2Dist = bridge2Data(:, 3);
[row1, col1] = size(bridge1Dist);
[row2, col2] = size(bridge2Dist);
bridge1Disp = zeros(row1, col1);
bridge2Disp = zeros(row2, col2);
fdValue1 = 0.000407350000000029;
&Main code
%Displacement
for k = 2:length(bridge1Dist)
bridge1Disp(k-1, 1) = bridge1Dist(k, 1) - bridge1Dist(k-1, 1);
end
%Max Load Bridge 1
maxLoad1 = 0;
for n = 1:length(bridge1Load)
for k = 1
if bridge1Load(n, k) > maxLoad1
maxLoad1 = bridge1Load(n, k);
end
end
end
%Cycle through data till failure, change proj data
totalRect1 = 0;
for j = 2:length(bridge1Disp)
while bridge1Disp(j, 1) ~= fdValue1
rectangle = (bridge1Disp(j, 1) - bridge1Disp(j-1, 1))*...
((bridge1Load(j, 1) + bridge1Load(j-1, 1))/2);
totalRect1 = totalRect1 + rectangle;
end
end
Basically, I make an array for the load and distance the machine pushes down on the bridge, assign a 'Failure Distance' value (fdValue) which should be used to determine when we stop calculating toughness. I then calculate displacement, calculate the maximum load. Then through the variable 'rectangle', calculate each rectangle and sum them all up in 'totalRect1', and use that to calculate the toughness by finding the area under the curve. Is anyone able to see why the loop is an infinite loop?
Thanks
The problem with the condition while bridge1Disp(j, 1) ~= fdValue1 is that you need to check for <= and not for (in)equality, since double numbers will almost never evaluate to be equal even if they seem so. To read more about this you can look here and also google for matlab double comparison. Generally it has something to do with precision issues.
Usually when checking for double equality you should use something like if abs(val-TARGET)<1E-4, and specify some tolerance which you are willing to permit.
Regardless,
You don't need to use loops for what you're trying to do. I'm guessing this comes from some C-programming habits, which are not required in MATLAB.
The 1st loop (Displacement), which computes the difference between every two adjacent elements can be replaced by the function diff like so:
bridge1Disp = diff(bridge1Dist);
The 2nd loop construct (Max Load Bridge 1), which retrieves the maximum element of bridge1Load can be replaced by the command max as follows:
maxLoad1 = max(bridge1Load);
For the last loop construct (Cycle ...) consider the functions I've mentioned above, and also find.
In the code section
%Cycle through data till failure, change proj data
totalRect1 = 0;
for j = 2:length(bridge1Disp)
while bridge1Disp(j, 1) ~= fdValue1
rectangle = (bridge1Disp(j, 1) - bridge1Disp(j-1, 1))*...
((bridge1Load(j, 1) + bridge1Load(j-1, 1))/2);
totalRect1 = totalRect1 + rectangle;
end
end
the test condition of the while loop is
bridge1Disp(j, 1) ~= fdValue1
nevertheless, in the while loop the value of bridge1Disp(j, 1) does not change so if at the first iteratiion of the while loop bridge1Disp(j, 1) is ~= fdValue1 the loop will never end.
Hope this helps.
I am trying to generate an array from some starting values using this formula in MATLAB:
yt = a0 + ∑i=1p (ai ⋅ yt-i), t ≥ p
p is some small number compared to T (max t). I have been able to make this using two for cycles but it is really slow. Is there some easy way to do it?
First p values of y are provided and vector a (its length is p+1) is provided too...
This is what I have so far, but now when I tried it, it doesn't work 100% (I think it's because of indexing from 1 in MATLAB):
y1 = zeros(T+1, 1);
y1(1:p) = y(1:p);
for t = p+1:T+1
value = a1(1);
for j = 2:p+1
value = value + a1(j)*y1(t-j+1);
end
y1(t) = value;
end
EDIT: I solved it, I am just not used to Matlab indexing from 1...
This statement
if(p>=t)
looks odd inside a loop whose index expression is
for t = p+1:T+1
which seems to guarantee that t>p for the entire duration of the loop. Is that what you meant to write ?
EDIT in response to comment
Inside a loop indexed with this statement
for j = 2:p
how does the reference you make to a(j) ever call for a(0) ?
y1 = zeros(T+1, 1);
y1(1:p) = y(1:p);
for t = p+1:T+1
value = a1(1);
for j = 2:p+1
value = value + a1(j)*y1(t-j+1);
end
y1(t) = value;
end
I have a matrix with integers and I need to replace all appearances of 2 with -5. What is the most efficient way to do it? I made it the way below, but I am sure there is more elegant way.
a=[1,2,3;1,3,5;2,2,2]
ind_plain = find(a == 2)
[row_indx col_indx] = ind2sub(size(a), ind_plain)
for el_id=1:length(row_indx)
a(row_indx(el_id),col_indx(el_id)) = -5;
end
Instead of loop I I seek for something like: a(row_indx,col_indx) = -5, which does not work.
find is not needed in this case.
Use logical indexing instead:
a(a == 2) = -5
In case of searching whether a matrix is equal to inf you should use
a(isinf(a)) = -5
The general case is:
Mat(boolMask) = val
where Mat is your matrix, boolMask is another matrix of logical values, and val is the assignment value
Try this:
a(a==2) = -5;
The somewhat longer version would be
ind_plain = find(a == 2);
a(ind_plain) = -5;
In other words, you can index a matrix directly using linear indexes, no need to convert them using ind2sub -- very useful! But as demonstrated above, you can get even shorter if you index the matrix using a boolean matrix.
By the way, you should put semicolons after your statements if (as is usually the case) you're not interested in getting the result of the statement dumped out to the console.
The Martin B's method is good if you are changing values in vector. However, to use it in matrix you need to get linear indices.
The easiest solution I found is to use changem function. Very easy to use:
mapout = changem(Z,newcode,oldcode)
In your case: newA = changem(a, 5, -2)
More info: http://www.mathworks.com/help/map/ref/changem.html
Here's a trivial, unoptimised, probably slow implementation of changem from the Mapping Toolbox.
function mapout = changem(Z, newcode, oldcode)
% Idential to the Mapping Toolbox's changem
% Note the weird order: newcode, oldcode. I left it unchanged from Matlab.
if numel(newcode) ~= numel(oldcode)
error('newcode and oldcode must be equal length');
end
mapout = Z;
for ii = 1:numel(oldcode)
mapout(Z == oldcode(ii)) = newcode(ii);
end
end
I have some massive matrix computation to do in MATLAB. It's nothing complicated (see below). I'm having issues with making computation in MATLAB efficient. What I have below works but the time it takes simply isn't feasible because of the computation time.
for i = 1 : 100
for j = 1 : 20000
element = matrix{i}(j,1);
if element <= bigNum && element >= smallNum
count = count + 1;
end
end
end
Is there a way of making this faster? MATLAB is meant to be good at these problems so I would imagine so?
Thank you :).
count = 0
for i = 1:100
count = count + sum(matrix{i}(:,1) <= bigNum & matrix{i}(:,1) >= smallNum);
end
If your matrix is a matrix, then this will do:
count = sum(matrix(:) >= smallNum & matrix(:) <= bigNum);
If your matrix is really huge, use anyExceed. You can profile (check the running time) of both functions on matrix and decide.