Gauss elimination to solve A*x = b linear system (MATLAB) - matlab

I'm trying to make a code that solves A*x = b, linear systems.
I made the code below using the gauss elimination process, and it works everytime if A doesn't have any 0's in it. If A has zeros in it, then sometimes it works, sometimes it doesn't. Basically I'm trying an alternative to the "A\b" in MATLAB.
Is there a better/simpler way of doing this?
A = randn(5,5);
b = randn(5,1);
nn = size(A);
n = nn(1,1);
U = A;
u = b;
for c = 1:1:n
k = U(:,c);
for r = n:-1:c
if k(r,1) == 0
continue;
else
U(r,:) = U(r,:)/k(r,1);
u(r,1) = u(r,1)/k(r,1);
end
end
for r = n:-1:(c+1)
if k(r,1) == 0
continue;
else
U(r,:) = U(r,:) - U(r-1,:);
u(r,1) = u(r,1) - u(r-1,1);
end
end
end
x = zeros(size(b));
for r = n:-1:1
if r == n
x(r,1) = u(r,1);
else
x(r,1) = u(r,1);
x(r,1) = x(r,1) - U(r,r+1:n)*x(r+1:n,1);
end
end
error = A*x - b;
for i = 1:1:n
if abs(error(i)) > 0.001
disp('ERROR!');
break;
else
continue;
end
end
disp('x:');
disp(x);
Working example with 0's:
A = [1, 3, 1, 3;
3, 4, 4, 1;
3, 0, 3, 9;
0, 4, 0, 1];
b = [3;
4;
5;
6];
Example that fails (A*x-b isn't [0])
A = [1, 3, 1, 3;
3, 4, 4, 1;
0, 0, 3, 9;
0, 4, 0, 1];
b = [3;
4;
5;
6];
Explanation of my algorithm:
Lets say I have the following A matrix:
|4, 1, 9|
|3, 4, 5|
|1, 3, 5|
For the first column, I divide each line by the first number in the row, so every row starts with 1
|1, 1/4, 9/4|
|1, 4/3, 5/3|
|1, 3, 5|
Then I subtract the last row with the one above it, and then I'll do the same for the row above and so on.
|1, 1/4, 9/4|
|0, 4/3-1/4, 5/3-9/4|
|0, 3-4/3, 5-5/3|
|1, 0.25, 2.250|
|0, 1.083, -0.5833|
|0, 1.667, 3.333|
Then I repeat the same for the rest of the columns.
|1, 0.25, 2.250|
|0, 1, -0.5385|
|0, 1, 1.999|
|1, 0.25, 2.250|
|0, 1, -0.5385|
|0, 0, -8.7700|
|1, 0.25, 2.250|
|0, 1, -0.5385|
|0, 0, 1|
The same operations I do in A I do in b so the system stays equivalent.
re-UPDATE:
I added this right after "for c = 1:1:n"
So before doing anything it sorts the rows of A (and b) in order to make the "c" column have decrescent entries (0's will be left on the bottom rows of A). Right now it seems to work for any invertible square matrix, although I'm not sure it will.
r = c;
a = r + 1;
while r <= n
if r == n
r = r + 1;
elseif a <= n
while a <= n
if abs(U(r,c)) < abs(U(a,c))
UU = U(r,:);
U(r,:) = U(a,:);
U(a,:) = UU;
uu = u(r,1);
u(r,1) = u(a,1);
u(a,1) = uu;
else
a = a+1;
end
end
else
r = r+1;
a = r+1;
end
end

Gaussian elimination with pivoting is as following.
function [L,U,P] = my_lu_piv(A)
n = size(A,1);
I = eye(n);
O = zeros(n);
L = I;
U = O;
P = I;
function change_rows(k,p)
x = P(k,:); P(k,:) = P(p,:); P(p,:) = x;
x = A(k,:); A(k,:) = A(p,:); A(p,:) = x;
x = v(k); v(k) = v(p); v(p) = x;
end
function change_L(k,p)
x = L(k,1:k-1); L(k,1:k-1) = L(p,1:k-1);
L(p,1:k-1) = x;
end
for k = 1:n
if k == 1, v(k:n) = A(k:n,k);
else
z = L(1:k-1,1:k -1)\ A(1:k-1,k);
U(1:k-1,k) = z;
v(k:n) = A(k:n,k)-L(k:n,1:k-1)*z;
end
if k<n
x = v(k:n); p = (k-1)+find(abs(x) == max(abs(x))); % find index p
change_rows(k,p);
L(k+1:n,k) = v(k+1:n)/v(k);
if k > 1, change_L(k,p); end
end
U(k,k) = v(k);
end
end
In order to solve the system..
% Ax = b (1) original system % LU = PA
(2) factorization of PA or A(p,:) into the product LU % PAx =
Pb (3) multiply both sides of (1) by P % LUx = Pb
(4) substitute (2) into (3) % let y = Ux (5) define y as
Ux % let c = Pb (6) define c as Pb % Ly = c
(7) subsitute (5) and (6) into (4) % U*x = y (8) a
rewrite of (5)
To do this..
% [L U p] = lu (A) ; % factorize % y = L \ (P*b) ; % forward
solve of (7), a lower triangular system % x = U \ y ; %
backsolve of (8), an upper triangular system

Gaussian algorithm assumes that the matrix is converted to an upper triangular matrix. This does not happen in your example. The result of your algorithm is
A =
1 3 1 3
3 4 4 1
0 0 3 9
0 4 0 1
U =
1.00000 3.00000 1.00000 3.00000
-0.00000 1.00000 -0.20000 1.60000
0.00000 0.00000 1.00000 3.00000
0.00000 4.00000 -0.00000 1.00000
As you can see, it's not upper triangular. You are skipping rows, if the pivot element is zero. That does not work. To fix this you need to swap columns in the matrix and rows in the vector if the pivot element is zero. At the end you have to swap back rows in your result b resp. u.
Gaussian algorithm is:
1 Set n = 1
2 Take pivot element (n, n)
3 If (n, n) == 0, swap column n with column m, so that m > n and (n, m) != 0 (swap row m and n in vector b)
4 Divide n-th row by pivot element (divide n-th row in vector b)
5 For each m > n
6 If (m, n) != 0
7 Divide row m by m and subtract element-wise row n (same for vector b)
8 n = n + 1
9 If n <= number of rows, go to line 2
In terms of numerical stability it would be best to use the maximum of each row as pivot element. Also you can use the maximum of the matrix as pivot element by swapping columns and rows. But remember to swap in b and to swap back in your solution.

Try this:
Ab = [A,b] % Extended matrix of the system of equations
rref(Ab) % Result of applying the Gauss-Jordan elimination to the extended matrix
See rref documentation for more details and examples.

Related

Triangular factorization with pivoting Matlab

I'm new to Octave and Matlab and I have a problem. I need to make a program, which solves a Triangular system of linear equations and making a triangular factorization with pivoting.
For example I need to do next exercise
That is my lufact function
function X = lufact (A, B)
[N, N] = size(A);
X = zeros(N, 1);
Y = zeros(N, 1);
C = zeros(1, N);
R = 1:N;
for p=1:N-1
[max1,j]=max(abs(A(p:N,p)));
C = A(p, :);
A(p, :) = A(j + p - 1, :);
A(j + p - 1, :) = C;
d = R(p);
R(p) = R(j + p - 1);
R(j + p - 1) = d;
if A(p,p) == 0
'A is singular. No unique solution'
break
endif
endfor
for k = p + 1: N
mult = A(k,p)/A(p,p);
A(k,p) = mult;
A(k, p + 1: N) = A(k, p + 1: N) - mult*A(p, p+1: N);
endfor
endfunction
Y(1) = B(R(1));
for k = 2: N
Y(k) = B(R(k)) - A(k, 1:k - 1)*Y(1:k - 1);
endfor
X(N) = Y(N)/A(N,N);
for k = N-1: -1: 1
X(k) = (Y(k) - A(k, k + 1: N)*X(k + 1: N))/A(k, k);
endfor
And that is my main function
A = [2 4 -6; 1 5 3; 1 3 2];
BA = [-4; 10; 5]
BB = [20; 49; 32]
XA = lufact(A, BA);
XB = lufact(A, BB);
disp(XA);
disp(XB);
The output of my program
What am I doing wrong and what should I do to fix that?
You don't seem to be attempting to answer the question you're asking, so your question doesn't make much sense...
But, in any case. The exercise asks you to show that given the following matrices / vectors:
A = [ 2, 4, -6; 1, 5, 3; 1, 3, 2 ];
L = [ 1, 0, 0; 1/2, 1, 0; 1/2, 1/3, 1 ];
U = [ 2, 4, -6; 0, 3, 6; 0, 0, 3 ];
show that LY = B, UX = Y, AX = B for a given B.
Ok. In octave, the best way to solve a matrix equation of the form aX = b w.r.t X for a given a and b, is to use the "matrix left-division" operator, \, i.e. x = a\b. Type help mldivide in your octave console for details.
So,
Y = L\B;
X = U\Y;
A*X % the result should be the same as B. QED.
Then there is the separate question of how can I perform LU decomposition in octave? Well, octave provides a function for this: lu.
[L, U] = lu(A)
% L = 1.0000 0 0
% 0.5000 1.0000 0
% 0.5000 0.3333 1.0000
%
% U = 2 4 -6
% 0 3 6
% 0 0 3
Then there's the implied further question of "I would like to perform LU decomposition by hand."
Great. Good luck. Your code here is a bit messy, no comments, no self-explanatory variable names ... I won't attempt to debug it here in detail. One thing to note though is, LU decomposition only takes a matrix as an input. I'm not sure why you are trying to pass the 'B' matrix to it as an input. Plus it doesn't seem like you're using it anywhere in the function. Or creating L or U matrices for that matter. Also, if the whole top part is inside an lufact.m file, then you should know that your function terminates well before the for loops; these get ignored completely. What were you trying to do exactly?

Plotting numbers in a Cell array

I want to just plot the data, which is all real numbers, that is stored in a Cell Array. My cell array is 1-100 1-dimensional, but I am confused on how to actually apply the plot() function with the hold on function.
Here is my code:
% Initalize arrays for storing data
C = cell(1,100); % Store output vector from floww()
D = cell(1,6); % User inputted initial point
I1 = cell(1,100);
I2 = cell(1,100);
I3 = cell(1,100);
%Declare alpha and beta variables detailed in Theorem 1 of paper
a1 = 0; a2 = 2; a3 = 4; a4 = 6;
b1 = 2; b2 = 3; b3 = 7; b4 = 10;
% Declare the \lambda_i, i=1,..., 6, variables
L = cell(1,6);
L1 = abs((b2 - b3)/(a2 - a3));
L2 = abs((b1 - b3)/(a1 - a3));
L3 = abs((b1 - b2)/(a1 - a2));
L4 = abs((b1 - b4)/(a1 - a4));
L5 = abs((b2 - b4)/(a2 - a4));
L6 = abs((b3 - b4)/(a3 - a4));
L{1,1} = L1;
L{1,2} = L2;
L{1,3} = L3;
L{1,4} = L4;
L{1,5} = L5;
L{1,6} = L6;
% Create function handle for floww()
F = #floww;
for j = 1:6
D{1,j} = input('Input in1 through in6: ');
end
% Iterate through floww()
k = [0:5:100];
for i = 1: 100
C{1,i} = F(D{1,1}, D{1,2}, D{1,3}, D{1,4}, D{1,5}, D{1,6},L); % Output from floww() is a 6-by-1 vector
for j = 1:6
D{1,j} = C{1,i}(j,1); % Reassign input values to put back into floww()
end
% First integrals as described in the paper
I1{1,i} = 2*(C{1,i}(1,1)).^2 + 2*(C{1,i}(2,1)).^2 + 2*(C{1,i}(3,1)).^2 + 2*(C{1,i}(4,1)).^2 + 2*(C{1,i}(5,1)).^2 + 2*(C{1,i}(6,1)).^2;
I2{1,i} = (-C{1,i}(3,1))*(-C{1,i}(6,1)) - (C{1,i}(2,1))*(-C{1,i}(5,1)) + (-C{1,i}(1,1))*(-C{1,i}(4,1));
I3{1,i} = 2*L1*(C{1,i}(1,1)).^2 + 2*L2*(C{1,i}(2,1)).^2 + 2*L3*(C{1,i}(3,1)).^2 + 2*L4*(C{1,i}(4,1)).^2 + 2*L5*(C{1,i}(5,1)).^2 + 2*L6*(C{1,i}(6,1)).^2;
plot(k, I1{1,i});
hold on;
end
% This function will solve the linear system
% Bx^(n+1) = x detailed in the research notes
function [out1] = floww(in1, in2, in3, in4, in5, in6, L)
% A_ij = (lambda_i - lambda_j)
% Declare relevant A_ij values
A32 = L{1,3} - L{1,2};
A65 = L{1,6} - L{1,5};
A13 = L{1,1} - L{1,3};
A46 = L{1,4} - L{1,6};
A21 = L{1,2} - L{1,1};
A54 = L{1,5} - L{1,4};
A35 = L{1,3} - L{1,5};
A62 = L{1,6} - L{1,2};
A43 = L{1,4} - L{1,3};
A16 = L{1,1} - L{1,6};
A24 = L{1,2} - L{1,4};
A51 = L{1,5} - L{1,1};
% Declare del(T)
delT = 1;
% Declare the 6-by-6 coefficient matrix B
B = [1, -A32*(delT/2)*in3, -A32*(delT/2)*in2, 0, -A65*(delT/2)*in6, -A65*(delT/2)*in5;
-A13*(delT/2)*in3, 1, -A13*(delT/2)*in1, -A46*(delT/2)*in6, 0, A46*(delT/2)*in4;
-A21*(delT/2)*in2, -A21*(delT/2)*in1, 1, -A54*(delT/2)*in5, -A54*(delT/2)*in4, 0;
0, -A62*(delT/2)*in6, -A35*(delT/2)*in5, 1, -A35*(delT/2)*in3, -A62*(delT/2)*in2;
-A16*(delT/2)*in6, 0, -A43*(delT/2)*in4, -A43*(delT/2)*in3, 1, -A16*(delT/2)*in1;
-A51*(delT/2)*in5, -A24*(delT/2)*in4, 0, -A24*(delT/2)*in2, -A51*(delT/2)*in1, 1];
% Declare input vector
N = [in1; in2; in3; in4; in5; in6];
% Solve the system Bx = N for x where x
% denotes the X_i^(n+1) vector in research notes
x = B\N;
% Assign output variables
out1 = x;
%disp(x);
%disp(out1(2,1));
end
The plotting takes place in the for-loop with plot(k, I1{1,i});. The figure that is outputted is not what I expect nor want:
Can someone please explain to me what I am doing wrong and/or how to get what I want?
You need to stop using cell arrays for numeric data, and indexed variable names when an array would be way simpler.
I've edited your code, below, to plot the I1 array.
To make it work, I changed almost all cell arrays to numeric arrays and simplified a bunch of the indexing. Note initialisation is now with zeros instead of cell, therefore indexing with parentheses () not curly braces {}.
I didn't change the structure too much, because your comments indicated you were following some literature with this layout
For the plotting, you were trying to plot single points during the loop - to do that you have no line (the points are distinct), so need to specify a marker like plot(x,y,'o'). However, what I've done is just plot after the loop - since you're storing the resulting I1 array anyway.
% Initalize arrays for storing data
C = cell(1,100); % Store output vector from floww()
D = zeros(1,6); % User inputted initial point
I1 = zeros(1,100);
I2 = zeros(1,100);
I3 = zeros(1,100);
%Declare alpha and beta variables detailed in Theorem 1 of paper
a1 = 0; a2 = 2; a3 = 4; a4 = 6;
b1 = 2; b2 = 3; b3 = 7; b4 = 10;
% Declare the \lambda_i, i=1,..., 6, variables
L = zeros(1,6);
L(1) = abs((b2 - b3)/(a2 - a3));
L(2) = abs((b1 - b3)/(a1 - a3));
L(3) = abs((b1 - b2)/(a1 - a2));
L(4) = abs((b1 - b4)/(a1 - a4));
L(5) = abs((b2 - b4)/(a2 - a4));
L(6) = abs((b3 - b4)/(a3 - a4));
for j = 1:6
D(j) = input('Input in1 through in6: ');
end
% Iterate through floww()
for i = 1:100
C{i} = floww(D(1), D(2), D(3), D(4), D(5), D(6), L); % Output from floww() is a 6-by-1 vector
for j = 1:6
D(j) = C{i}(j,1); % Reassign input values to put back into floww()
end
% First integrals as described in the paper
I1(i) = 2*(C{i}(1,1)).^2 + 2*(C{i}(2,1)).^2 + 2*(C{i}(3,1)).^2 + 2*(C{i}(4,1)).^2 + 2*(C{i}(5,1)).^2 + 2*(C{i}(6,1)).^2;
I2(i) = (-C{i}(3,1))*(-C{i}(6,1)) - (C{i}(2,1))*(-C{i}(5,1)) + (-C{i}(1,1))*(-C{i}(4,1));
I3(i) = 2*L(1)*(C{i}(1,1)).^2 + 2*L(2)*(C{i}(2,1)).^2 + 2*L(3)*(C{i}(3,1)).^2 + 2*L(4)*(C{i}(4,1)).^2 + 2*L(5)*(C{i}(5,1)).^2 + 2*L(6)*(C{i}(6,1)).^2;
end
plot(1:100, I1);
% This function will solve the linear system
% Bx^(n+1) = x detailed in the research notes
function [out1] = floww(in1, in2, in3, in4, in5, in6, L)
% A_ij = (lambda_i - lambda_j)
% Declare relevant A_ij values
A32 = L(3) - L(2);
A65 = L(6) - L(5);
A13 = L(1) - L(3);
A46 = L(4) - L(6);
A21 = L(2) - L(1);
A54 = L(5) - L(4);
A35 = L(3) - L(5);
A62 = L(6) - L(2);
A43 = L(4) - L(3);
A16 = L(1) - L(6);
A24 = L(2) - L(4);
A51 = L(5) - L(1);
% Declare del(T)
delT = 1;
% Declare the 6-by-6 coefficient matrix B
B = [1, -A32*(delT/2)*in3, -A32*(delT/2)*in2, 0, -A65*(delT/2)*in6, -A65*(delT/2)*in5;
-A13*(delT/2)*in3, 1, -A13*(delT/2)*in1, -A46*(delT/2)*in6, 0, A46*(delT/2)*in4;
-A21*(delT/2)*in2, -A21*(delT/2)*in1, 1, -A54*(delT/2)*in5, -A54*(delT/2)*in4, 0;
0, -A62*(delT/2)*in6, -A35*(delT/2)*in5, 1, -A35*(delT/2)*in3, -A62*(delT/2)*in2;
-A16*(delT/2)*in6, 0, -A43*(delT/2)*in4, -A43*(delT/2)*in3, 1, -A16*(delT/2)*in1;
-A51*(delT/2)*in5, -A24*(delT/2)*in4, 0, -A24*(delT/2)*in2, -A51*(delT/2)*in1, 1];
% Declare input vector
N = [in1; in2; in3; in4; in5; in6];
% Solve the system Bx = N for x where x
% denotes the X_i^(n+1) vector in research notes
x = B\N;
% Assign output variables
out1 = x;
end
Output with in1..6 = 1 .. 6:
Note: you could simplify this code a lot if you embraced arrays over clunky variable names. The below achieves the exact same result for the body of your script, but is much more flexible and maintainable:
See how much simpler your integral expressions become!
% Initalize arrays for storing data
C = cell(1,100); % Store output vector from floww()
D = zeros(1,6); % User inputted initial point
I1 = zeros(1,100);
I2 = zeros(1,100);
I3 = zeros(1,100);
%Declare alpha and beta variables detailed in Theorem 1 of paper
a = [0, 2, 4, 6];
b = [2, 3, 7, 10];
% Declare the \lambda_i, i=1,..., 6, variables
L = abs( ( b([2 1 1 1 2 3]) - b([3 3 2 4 4 4]) ) ./ ...
( a([2 1 1 1 2 3]) - a([3 3 2 4 4 4]) ) );
for j = 1:6
D(j) = input('Input in1 through in6: ');
end
% Iterate through floww()
k = 1:100;
for i = k
C{i} = floww(D(1), D(2), D(3), D(4), D(5), D(6), L); % Output from floww() is a 6-by-1 vector
D = C{i}; % Reassign input values to put back into floww()
% First integrals as described in the paper
I1(i) = 2*sum(D.^2);
I2(i) = sum( D(1:3).*D(4:6) );
I3(i) = 2*sum((L.').*D.^2).^2;
end
plot( k, I1 );
Edit:
You can simplify the floww function by using a couple of things
A can be declared really easily as a single matrix.
Notice delT/2 is a factor in almost every element, factor it out!
The only non-zero elements where delT/2 isn't a factor are the diagonal of ones... add this in using eye instead.
Input the in1..6 variables as a vector. You already have the vector when you call floww - makes no sense breaking it up.
With the input as a vector, we can use utility functions like hankel to do some neat indexing. This one is a stretch for a beginner, but I include it as a demo.
Code:
% In code body, call floww with an array input
C{i} = floww(D, L);
% ...
function [out1] = floww(D, L)
% A_ij = (lambda_i - lambda_j)
% Declare A_ij values in a matrix
A = L.' - L;
% Declare del(T)
delT = 1;
% Declare the 6-by-6 coefficient matrix B
% Factored out (delt/2) and the D coefficients
B = eye(6,6) - (delT/2) * D( hankel( [4 3 2 1 6 5], [5 4 3 2 1 6] ) ) .*...
[ 0, A(3,2), A(3,2), 0, A(6,5), A(6,5);
A(1,3), 0, A(1,3), A(4,6), 0, -A(4,6);
A(2,1), A(2,1), 0, A(5,4), A(5,4), 0;
0, A(6,2), A(3,5), 0, A(3,5), A(6,2);
A(1,6), 0, A(4,3), A(4,3), 0, A(1,6);
A(5,1), A(2,4), 0, A(2,4), A(5,1), 0];
% Solve the system Bx = N for x where x
% denotes the X_i^(n+1) vector in research notes
out1 = B\D(:);
end
You see when we simplify things like this, code is easier to read. For instance, it looks to me (without knowing the literature at all) like you've got a sign error in your B(2,6) element, it's the opposite sign to all other elements...

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

How can I do vectorization for this matlab "for loop"?

I have some matlab code as follow, constructing KNN similarity weight matrix.
[D,I] = pdist2(X, X, 'squaredeuclidean', 'Smallest', k+1);
D = D < threshold;
W = zeros(n, n);
for i=1:size(I,2)
W(I(:,i), i) = D(:,i);
W(i, I(:,i)) = D(:,i)';
end
I want to vectorize the for loop. I have tried
W(I) = D;
but failed to get the correct value.
I add test case here:
n = 5;
D = [
1 1 1 1 1
0 1 1 1 1
0 0 0 0 0
];
I = [
1 2 3 4 5
5 4 5 2 3
3 1 1 1 1
];
There are some undefined variables that makes it hard to check what it is doing, but this should do the same as your for loop:
D,I] = pdist2(X, X, 'squaredeuclidean', 'Smallest', k+1);
D = D < threshold;
W = zeros(n);
% set the diagonal values
W(sub2ind(size(X), I(1, :), I(1, :))) = D(1,:);
% set the other values
W(sub2ind(size(W), I(2, :), 1:size(I, 2))) = D(2, :);
W(sub2ind(size(W), 1:size(I, 2), I(2, :))) = D(2, :).';
I splited the directions, it works now with your test case.
A possible solution:
idx1 = reshape(1:n*n,n,n).';
idx2 = bsxfun(#plus,I,0:n:n*size(I,2)-1);
W=zeros(n,n);
W(idx2) = D;
W(idx1(idx2)) = D;
Here assumed that you repeatedly want to compute D and I so compute idx only one time and use it repeatedly.
n = 5;
idx1 = reshape(1:n*n,n,n).';
%for k = 1 : 1000
%[D,I] = pdist2(X, X, 'squaredeuclidean', 'Smallest', k+1);
%D = D < threshold;
idx2 = bsxfun(#plus,I,0:n:n*size(I,2)-1);
W=zeros(n,n);
W(idx2) = D;
W(idx1(idx2)) = D;
%end
But if n isn't constant and it varies in each iteration it is better to change the way idx1 is computed:
n = 5;
%for k = 1 : 1000
%n = randi([2 10]);%n isn't constant
%[D,I] = pdist2(X, X, 'squaredeuclidean', 'Smallest', k+1);
%D = D < threshold;
idx1 = bsxfun(#plus,(0:n:n^2-1).',1:size(I,2));
idx2 = bsxfun(#plus,I,0:n:n*size(I,2)-1);
W=zeros(n,n);
W(idx2) = D;
W(idx1(idx2)) = D;
%end
You can cut some corners with linear indices but if your matrices are big then you should only take the nonzero components of D. Following copies all values of D
W = zeros(n);
W(reshape(sub2ind([n,n],I,[1;1;1]*[1:n]),1,[])) = reshape(D,1,[]);

Matlab: Applying threshold to one dimension in a matrix

I have a matrix M(x,y). I want to apply a threshold in all values in x, such that if x
Example:
M = 1, 2;
3, 4;
5, 6;
If t = 5 is applied on the 1st dimension, the result will be
R = 0, 2;
0, 4;
5, 6;
One way (use M(:,1) to select the first column; M(:,1)<5 returns row indices for items in the first column that are lest than 5))-
> R = M;
> R(M(:,1)<5,1) = 0
R =
0 2
0 4
5 6
Another -
R = M;
[i,j]=find(M(:,1)<5); % locate rows (i) and cols (j) where M(:,1) < 5
% so j is just going to be all 1
% and i has corresponding rows
R(i,1)=0;
To do it in a matrix of arbitrary dimensions:
thresh_min = 5;
M(M < thresh_min) = 0;
The statement M < thresh_min returns indices of M that are less than thresh_min. Then, reindexing into M with these indices, you can set all of these valuse fitting your desired criterion to 0 (or whatever else).