Unary Operation Using For Loops In Matlab - matlab

I'm trying to do some basic arithmetic within a for loop in MatLab.
Basically I want to copy and operate on each element one-by-one. First I want to subtract 3.6: testDataMean from each element, raise each element to the power of 2 then sum up each variable. The finally divide the variable s by 5 (sizeOfTestData)
This should calculate approximately ~1.05.
The testData variable is a 1x5 vector containing the numbers 3, 4, 2, 5, 4
s = 0;
for k = 1:sizeTestData
p = testData(k);
q = p - testDataMean;
r = q^2;
s = s + r;
s/5;
end
This loop actually throws an error on the last line s = s + r. I am aware I can use the sum function in most circumstances when operating on vectors of the same size, but in the context of a for loop I'm not sure.

Note that sum(s) / numel(s) by definition is the same as mean(s).
The loop free approach:
testData = [3, 4, 2, 5, 4]
q = testData - mean(testData);
s = mean(q.^2);
s = 1.0400
The one-liner:
s = mean((testData-mean(testData)).^2)
s = 1.0400
And your initial approach:
(After bug fixing)
testData = [3, 4, 2, 5, 4]
s = 0;
sizeTestData = length(testData);
testDataMean = mean(testData);
for k = 1:sizeTestData
p = testData(k);
q = p - testDataMean;
r = q^2;
s = s + r;
end
s = s / numel(s);
s = 1.0400

Related

Vectorization of a loop in matlab

I have a loop
for i = 2:K
T(K,i) = ((4^(i-1))*T(K,i-1)-T(K-1,i-1))/(4^(i-1)-1);
end
where T is a two dimensional matrix (first element in given row, and all elements in rows above are already there) and K is a scalar.
I have tried to vectorize this loop to make it faster like this:
i = 2:K;
T(K,i) = ((4.^(i-1)).*T(K,i-1)-T(K-1,i-1))./(4.^(i-1)-1);
it compiles, but it yields improper results. Can you tell me where am I making mistake?
#EDIT:
I have written this, but still the result is wrong
i = 2:K;
i2 = 1:(K-1);
temp1 = T(K,i2)
temp2 = T(K-1,i2)
T(K,i) = ((4.^(i2)).*temp1-temp2)./(4.^(i2)-1);
First, let's re-index your loop (having fewer i-1 expressions):
for i=1:K-1
T(K,i+1) = ( 4^i*T(K,i) - T(K-1,i) ) / (4^i-1);
end
Then (I'll leave out the loop for now), we can factor out 4^i/(4^i-1):
T(K,i+1) = ( T(K,i) - T(K-1,i)/4^i ) * (4^i/(4^i-1));
Let's call a(i) = (4^i/(4^i-1)), b(i) = - T(K-1,i)/4^i, then expanding the first terms we get:
T(K,1) = T(K,1)
T(K,2) = T(K,1)*a(1) + b(1)*a(1)
T(K,3) = T(K,1)*a(1)*a(2) + b(1)*a(1)*a(2) + b(2)*a(2)
T(K,4) = T(K,1)*a(1)*a(2)*a(3) + b(1)*a(1)*a(2)*a(3) + b(2)*a(2)*a(3) + b(3)*a(3)
Then with c = [1, a(1), a(1)*a(2), ...] = [1, cumprod(a)]
T(K,i) = (T(K,1) + (b(1)/c(1) + b(2)/c(2) + ... + b(i-1)/c(i-1) ) * c(i)
So with d = b ./ c, e = cumsum(d), summarizing all calculations:
i=1:K-1;
a = 4.^i./(4.^i-1);
b = -T(K-1,1:end-1) ./ 4.^i;
c = [1, cumprod(a)];
d = b ./ c(1:end-1);
e = cumsum(d);
T(K,2:K) = (T(K,1) + e) .* c(2:end);
To further optimize this, note that 4^14/(4^14 - 1) equals 1, when calculated with double-precision, so actually T(K,14:K) could be optimized drastically -- i.e., you actually just need to calculate a, c, 1./c up to index 13. (I'll leave that as an exercise).

Selecting elements from a large matrix using a sliding window

I have a 220*366 matrix, I want to set a 3*3 windows to select elements in matrix.
example:
matrix = [1, 2, 3, 4, 5;
6, 7, 8, 9, 10;
11,12,13,14,15];
window = [1, 2, 3;
6, 7, 8;
11,12,13];
If you have the Image Processing Toolbox, this can be done using nlfilter:
function out = q52158450()
% Create a matrix:
Rm = 220; Cm = 366;
matrix = randn(Rm,Cm);
% Define the window and apply filter:
Rw = 6; Rc = 6;
windows = nlfilter(matrix, [Rw, Rc], #getwindow);
% Select subset of outputs, removing zero-padded boundary elements:
Bw = floor((Rw-1)/2); Bc = floor((Rc-1)/2);
out = windows(Bw:end-Bw, Bc:end-Bc); % < Output is a cell
function out = getwindow(in)
out = {in};
Otherwise it can be done with a double loop:
function out = q52158450()
% Create a matrix:
Rm = 220; Cm = 366;
matrix = randn(Rm,Cm);
% Define the window and apply filter:
Wr = 3; Wc = 3;
Br = ceil(Wr/2); Bc = ceil(Wc/2);
out = cell(Rm-Br, Cm-Bc);
for indR = 1:Rm-Wr+1
for indC = 1:Cm-Wc+1
out{indR, indC} = matrix(indR:indR + Wr - 1, indC:indC + Wc - 1);
end
end

Is there a function making an adjacency matrix from index vector in matlab?

I have a vector set as follows:
S = { [14, 2, 11, 10, 3, 8, 7, 1], [15, 4, 8, 7, 1], [16, 5, 4, 8, 7, 1] };
For example, S{1} means that there exists edges between (14,2), (2,11), (11,10), (10,3), (3,8), (8,7), (7,1).
I want to make an adjacency matrix based on S. My code is as follows:
N = 20;
A = zeros(N);
for i=1:length(S)
for j=1:length(S{i})-1
from = S{i}(j);
to = S{i}(j+1);
A(from, to) = 1;
A(to, from) = 1;
end
end
Is there a function working like my code?
I think the existing code is much faster than my C-code-like code.
I'm not familiar with a function for creating an adjacency matrix without first constructing a graph. If you're just looking for a faster implementation then the following might work for you. For small problems like the one you posted it doesn't work any faster, but for big problems it seems to be about 4-5 times faster.
A = zeros(N);
for idx=1:numel(S)
s = S{idx};
from = s(1:end-1);
to = s(2:end);
A(([to from]-1)*N+[from to]) = 1;
end
Here's the big example problem I created for testing purposes.
N = 1000;
S = cell(1,1000);
for idx = 1:numel(S)
r = randperm(N);
S{idx} = r;
end
Timing difference using MATLAB2017a:
Your method: 0.149983 seconds.
This method: 0.036491 seconds.

Multidimensional data storage and interpolation

I have a function (so to speak, i actually have data with this characteristic) with one variable x and several parameters a, b and c, so y = f(x, a, b, c).
Now i want to interpolate within families of parameters (for example for variations of a).
I'm currently doing this for data with one parameter (here, y is the data matrix)
% generate variable and data
x = linspace(0, 1, 100);
a = [0, 1]; % parameter
for i = 1:length(a)
y(:, i) = x.^2 + a(i);
end
% interpolate:
yi = interp1(a, y.', 0.5);
This works fine, but how do i expand this to more dimensions?
My current data format is like this: Each column of my data matrix represents one specific set of parameters, so for example:
0 0 0 0
1 1 1 1
2 2 2 2
3 3 3 3
where the first column denotes a = 0, b = 0, the second a = 1, b = 0, the third a = 0, b = 1 and the last a = 1, b = 1 (values are just for clarification, this is not on purpose binary. Also, the data columns are obviously not the same).
This data format is just the consequence of my data aquisition scheme, but i'm happy to change this into something more useful. Whatever works.
Works well for me:
% generate variable and data
x = linspace(0, 1, 100);
a = [0, 1, 2]; % parameter
b = [3, 4, 5]; % parameter
c = [6, 7, 8]; % parameter
% Create grid
[X,A,B,C]=ndgrid(x,a,b,c);
% define function
foo = #(x,p1,p2,p3) p1.*x.^2 + p2.*x + p3;
% evaluate function
Y = foo(X,A,B,C);
% interpolate:
yi = interpn(X,A,B,C,Y,x,1,4,6);
#zlon's answer works fine for the interpolation part, here i want to show how to convert the data from the format i provided to the needed format for the interpolation.
The two-dimensional matrix must be transformed into a N-dimensional one. Since the columns are not necessarily in order, we need to find the right ones. This is what i did:
First, we need to know the parameter set of each column:
a = [ 2, 2, 1, 0, 0, 1 ];
b = [ 1, 0, 0, 1, 0, 1 ];
These vectors length match the number of columns in the data matrix. The first column for example now contains the data for a = 2 and b = 1.
Now we can generate the new table:
A = -Inf;
i = 1;
while true
A = min(a(a > A)); % find next a
if isempty(A)
break
end
idxa = find(a == A); % store possible indices
B = -Inf;
j = 1;
while true
B = min(b(b > B))); % find next b
if isempty(B)
break
end
idxb = find(b == B); % store possible indices
% combine both indices
idx = intersect(idxa, idxb);
% save column in new data table
data(:, i, j) = olddata(:, idx);
% advance
j = j + 1;
end
i = i + 1;
end

For loop output as an array

I wrote a code in Matlab which I predefine the variable "a" and then set up a for loop of 5 iterations where the variable "a" goes through some basic operations. However, the for loop output only saves the fifth iteration of "a." How do I save all 5 iterations in a 1x5 array?
The code is as follows:
a = 10;
k = 0.5;
n = 2;
for m = 1:5
a = a + (a*k) + n;
end
Edit:
I just found it that I have to create a new variable.
a = 10;
k = 0.5;
n = 2;
a_n = zeros(1,5);
for m = 1:5
a = a + (a*k) + n;
a_n(m) = a;
end
You may need to store value of a after each iteration into an another variable x
a = 10;
k = 0.5;
n = 2;
for m = 1:5
a = a + (a*k) + n;
x(m) = a;
end
x
Output:
x =
17.000 27.500 43.250 66.875 102.312
You would need to use a different variable to store the 5 iterations as an array.
Code would look something like this:
a = 10;
k = 0.5;
n = 2;
b = [];
for m = 1:5
a = (a + (a*k) + n)
b = [b a];
end
You can now print b for all 5 iteration values.
Here is an alternate way to update values into the 1-D matrix.