Swapping rows in a row echelon - matlab

I'm trying to make a program that computes, given any matrix A, its echelon form. Here is my code:
function A = myrref(A)
[m,n]=size(A);
for j=1:min(m,n)
A(j,:) = A(j,:)/A(j,j);
for i = j+1:m
A(i,:)= A(i,:)- A(j,:)*A(i,j);
if A(i,i) == 0
row1=A(i,:);
A(i,:)=A(i+1,:);
A(i+1,:)=row1;
end
end
end
It seems to work almost fine, but I still have a problem when swapping rows. For instance, when trying to get echelon form of matrix A=[1 1 1; 2 2 1; 1 2 2], I obtain [1 1 1; 0.5 1 1; 0 0 -1] which is not what I want. Do I need to add another loop that takes care of the 0.5 in the second row first column?

Firstly, it is simplier to use while loop for j because j is not necessarily growing on each iteration. The leading coefficient is not necessarily located on the main diagonal; when all the elements below the leading 0 are zeros, the leading coefficient position shifts to the right.
Secondly, the leading coefficient should be checked before A(j,:)/A(j,j) (to prevent division by 0)
Thirdly, the temporary is not needed to swap the rows as A([i j],:)= A([j i],:)
swaps the ith and jth rows of A.
Here is my version of myrref:
function A = myrref(A)
[m,n]=size(A);
j= 1; % the row index of the leading coefficient position
k= 1; % the column index of the leading coefficient position
while j<m && k<=n
if A(j,k)==0 % we need to change the row order
zeroindex= find(A(j+1:end,k)~=0); % find nonzero elements below A(j,k)
if isempty(zeroindex)
k= k+1; % there is no such elements; shift to the right
else
% swap the rows
A([j zeroindex(1)+j],:)= A([zeroindex(1)+j j],:);
end
else
A(j,:) = A(j,:)/A(j,k);
for i= j+1:m
A(i,:)= A(i,:)- A(j,:)*A(i,k);
end
j= j+1; k= k+1;
end
end

Just as #percusse said you need to finish the loop also your pivot should only go to m-1
Edit: Added an initial pivot based on #AVK's comment
function A = myrref(A)
[m,n]=size(A);
for i = 1:m-1
if A(i,i) == 0
row1=A(i,:);
A(i,:)=A(i+1,:);
A(i+1,:)=row1;
end
end
for j=1:min(m,n)
A(j,:) = A(j,:)/A(j,j);
for i = j+1:m
A(i,:)= A(i,:)- A(j,:)*A(i,j);
end
for i = j+1:m-1
if A(i,i) == 0
row1=A(i,:);
A(i,:)=A(i+1,:);
A(i+1,:)=row1;
end
end
end

Related

Output 1, 0.5, or 0 depending if a matrix elements are prime, 1, or neither

I am sending a matrix to my function modifikuj, where I want to replace the elements of the matrix with:
1 if element is a prime number
0 if element is a composite number
0.5 if element is 1
I dont understand why it is not working. I just started with MATLAB, and I created this function:
function B = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j))
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
With
A = [1,2;3,4];
D = modifikuj(A);
D should be:
D=[0.5, 1; 1 0];
In MATLAB you'll find you can often avoid loops, and there's plenty of built in functions to ease your path. Unless this is a coding exercise where you have to use a prescribed method, I'd do the following one-liner to get your desired result:
D = isprime( A ) + 0.5*( A == 1 );
This relies on two simple tests:
isprime( A ) % 1 if prime, 0 if not prime
A == 1 % 1 if == 1, 0 otherwise
Multiplying the 2nd test by 0.5 gives your desired condition for when the value is 1, since it will also return 0 for the isprime test.
You are not returning anything from the function. The return value is supposed to be 'B' according to your code but this is not set. Change it to A.
You are looping k until A(i,j) which is always divisible by itself, loop to A(i,j)-1
With the code below I get [0.5,1;1,0].
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j)-1)
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
In addition to #EuanSmith's answer. You can also use the in built matlab function in order to determine if a number is prime or not.
The following code will give you the desired output:
A = [1,2;3,4];
A(A==1) = 0.5; %replace 1 number with 0.5
A(isprime(A)) = 1; %replace prime number with 1
A(~ismember(A,[0.5,1])) = 0; %replace composite number with 0
I've made the assumption that the matrice contains only integer.
If you only want to learn, you can also preserve the for loop with some improvement since the function mod can take more than 1 divisor as input:
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
k = A(i,j);
if (k == 1)
A(i,j) = 0.5;
else
if all(mod(k,2:k-1)) %check each modulo at the same time.
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
And you can still improve the prime detection:
2 is the only even number to test.
number bigger than A(i,j)/2 are useless
so instead of all(mod(k,2:k-1)) you can use all(mod(k,[2,3:2:k/2]))
Note also that the function isprime is a way more efficient primality test since it use the probabilistic Miller-Rabin algorithme.

Problem to add element to matrix in if-else condition in Matlab

I'm writing a simple program to implement Artificial Neural Network to recognize handwritten characters using Matlab. I used following code to set Target data according to different characters.
Here is a part of code:
load('dataset.mat')
Target_Set=zeros(2,400); %Initialize Target array with 0s
%Set dimensions to resize
h = 50;
w = 45;
imgSize = h*w;
for j=1:4
for i=1:10
for k=1:10
Temp_Struct = struct('im',imresize(handwriting(i,j,k).im,[h,w]));
n = 100*(j-1) + 10*(i-1) + k;
P_Set(1:imgSize,n) = reshape(Temp_Struct.im,[imgSize,1]);
%Set Target patterns...
if (j==1) %When character I % Target Patterns...
Line 19========>Target_Set(0,n) = 1; % I J K L
Target_Set(1,n) = 0; % 0 1 0 1
elseif(j==2) %When character J % 0 0 1 1
Target_Set(0,n) = 1;
Target_Set(1,n)=0;
elseif(j==3) %When character K
Target_Set(0,n) = 0;
Target_Set(1,n)=1;
else %When character L
Target_Set(0,n) = 1;
Target_Set(1,n)=1;
end;
end;
end;
end;
When I run this, I got some error like this.
I couldn't understand why that kind of error occur in line 19. Welcome for any help.
Arrays in Matlab start at index number 1. So it is complaining about your use of a 0 value as an array index.
It should be correct like this.
Target_Set(1,n) = 0;

Vectorising a code using xor in Matlab

I have an mxn array r in Matlab with elements that are zeros or ones.
I want to construct a vector p of dimension mxn such that for i=1,...,m
p(i,1)=r(i,1)
p(i,2)=r(i,2)XOR r(i,1)
p(i,3)=r(i,3) XOR r(i,2)
...
p(i,n)=r(i,n) XOR r(i,n-1)
This code does what I want but it is slow for m,n large. Could you suggest something faster?
m=4;
n=5;
r=[1 1 1 1 1; ...
0 0 1 0 0; ...
1 0 1 0 1; ...
0 1 0 0 0];
p=zeros(m,n);
for i=1:m
p(i,1)=r(i,1);
for j=2:n
p(i,j)=xor(r(i,j),r(i,j-1));
end
end
Sure:
p = zeros(m,n);
p(:,1) = r(:,1);
p(:,2:end) = xor( r(:,1:(end-1)), r(:,2:n) );
What we're doing here is:
Pre-allocating the array. Same as your code.
Fill in the first column of p with the first column of r
Fill in the 2nd - last columns of p with the desired XOR operation. As inputs to the XOR we are using two large sections of r. The first is the 1st - (last-1)th columns. The second is the 2nd through last columns.

Replacing zeros (or NANs) in a matrix with the previous element row-wise or column-wise in a fully vectorized way

I need to replace the zeros (or NaNs) in a matrix with the previous element row-wise, so basically I need this Matrix X
[0,1,2,2,1,0;
5,6,3,0,0,2;
0,0,1,1,0,1]
To become like this:
[0,1,2,2,1,1;
5,6,3,3,3,2;
0,0,1,1,1,1],
please note that if the first row element is zero it will stay like that.
I know that this has been solved for a single row or column vector in a vectorized way and this is one of the nicest way of doing that:
id = find(X);
X(id(2:end)) = diff(X(id));
Y = cumsum(X)
The problem is that the indexing of a matrix in Matlab/Octave is consecutive and increments columnwise so it works for a single row or column but the same exact concept cannot be applied but needs to be modified with multiple rows 'cause each of raw/column starts fresh and must be regarded as independent. I've tried my best and googled the whole google but coukldn’t find a way out. If I apply that same very idea in a loop it gets too slow cause my matrices contain 3000 rows at least. Can anyone help me out of this please?
Special case when zeros are isolated in each row
You can do it using the two-output version of find to locate the zeros and NaN's in all columns except the first, and then using linear indexing to fill those entries with their row-wise preceding values:
[ii jj] = find( (X(:,2:end)==0) | isnan(X(:,2:end)) );
X(ii+jj*size(X,1)) = X(ii+(jj-1)*size(X,1));
General case (consecutive zeros are allowed on each row)
X(isnan(X)) = 0; %// handle NaN's and zeros in a unified way
aux = repmat(2.^(1:size(X,2)), size(X,1), 1) .* ...
[ones(size(X,1),1) logical(X(:,2:end))]; %// positive powers of 2 or 0
col = floor(log2(cumsum(aux,2))); %// col index
ind = bsxfun(#plus, (col-1)*size(X,1), (1:size(X,1)).'); %'// linear index
Y = X(ind);
The trick is to make use of the matrix aux, which contains 0 if the corresponding entry of X is 0 and its column number is greater than 1; or else contains 2 raised to the column number. Thus, applying cumsum row-wise to this matrix, taking log2 and rounding down (matrix col) gives the column index of the rightmost nonzero entry up to the current entry, for each row (so this is a kind of row-wise "cummulative max" function.) It only remains to convert from column number to linear index (with bsxfun; could also be done with sub2ind) and use that to index X.
This is valid for moderate sizes of X only. For large sizes, the powers of 2 used by the code quickly approach realmax and incorrect indices result.
Example:
X =
0 1 2 2 1 0 0
5 6 3 0 0 2 3
1 1 1 1 0 1 1
gives
>> Y
Y =
0 1 2 2 1 1 1
5 6 3 3 3 2 3
1 1 1 1 1 1 1
You can generalize your own solution as follows:
Y = X.'; %'// Make a transposed copy of X
Y(isnan(Y)) = 0;
idx = find([ones(1, size(X, 1)); Y(2:end, :)]);
Y(idx(2:end)) = diff(Y(idx));
Y = reshape(cumsum(Y(:)), [], size(X, 1)).'; %'// Reshape back into a matrix
This works by treating the input data as a long vector, applying the original solution and then reshaping the result back into a matrix. The first column is always treated as non-zero so that the values don't propagate throughout rows. Also note that the original matrix is transposed so that it is converted to a vector in row-major order.
Modified version of Eitan's answer to avoid propagating values across rows:
Y = X'; %'
tf = Y > 0;
tf(1,:) = true;
idx = find(tf);
Y(idx(2:end)) = diff(Y(idx));
Y = reshape(cumsum(Y(:)),fliplr(size(X)))';
x=[0,1,2,2,1,0;
5,6,3,0,1,2;
1,1,1,1,0,1];
%Do it column by column is easier
x=x';
rm=0;
while 1
%fields to replace
l=(x==0);
%do nothing for the first row/column
l(1,:)=0;
rm2=sum(sum(l));
if rm2==rm
%nothing to do
break;
else
rm=rm2;
end
%replace zeros
x(l) = x(find(l)-1);
end
x=x';
I have a function I use for a similar problem for filling NaNs. This can probably be cutdown or sped up further - it's extracted from pre-existing code that has a bunch more functionality (forward/backward filling, maximum distance etc).
X = [
0 1 2 2 1 0
5 6 3 0 0 2
1 1 1 1 0 1
0 0 4 5 3 9
];
X(X == 0) = NaN;
Y = nanfill(X,2);
Y(isnan(Y)) = 0
function y = nanfill(x,dim)
if nargin < 2, dim = 1; end
if dim == 2, y = nanfill(x',1)'; return; end
i = find(~isnan(x(:)));
j = 1:size(x,1):numel(x);
j = j(ones(size(x,1),1),:);
ix = max(rep([1; i],diff([1; i; numel(x) + 1])),j(:));
y = reshape(x(ix),size(x));
function y = rep(x,times)
i = find(times);
if length(i) < length(times), x = x(i); times = times(i); end
i = cumsum([1; times(:)]);
j = zeros(i(end)-1,1);
j(i(1:end-1)) = 1;
y = x(cumsum(j));

How to Put Matrix in a Look and store values?

I want to put one matrix in a look and want to get values of that matrix after that loop and want to store it. Example:
N =10;
C=eye(N);
P=[.1 .2 .3];
for k=1:3
Rp=C;
for i=1:N
if(rand < P(1,k))
Rp(i,:) = 0;
end
end
end
From the above function it is clear that i will get 3 Rp matrix as i have 3 values of P. How to store the values of all these 3 Rp? Any suggestions?
I think this is what you are looking for, just simply store the results at the end of the main loop into a cell array.
N=10;
C=eye(N);
p=[.1 .2 .3];
RpMats = cell(1,numel(p));
for k=1:numel(p)
Rp=C;
for i=1:N
if(rand < p(1,k))
Rp(i,:) = 0;
end
end
RpMats{k} = Rp;
end
RpMats is a cell array where index 1 corresponds with the probability at index 1.