MATLAB: Matrix Value Replacement Problem

matricieswrong index order

I'm intending on altering the values of a matrix (A) based on values in a another (B) in order to completely fill out the original matrix. Here's what I mean:
A= 0 0 0 1 0
0 1 0 1 0
1 0 0 0 1
0 0 0 0 1
1 0 0 1 1
B= 0 0 0 2 0
0 2 0 3 0
4 0 0 0 1
0 0 0 0 4
2 0 0 3 4
based on the value that appears at the corresponding location in matrix B determines which other location a point in A will populate. In other words if B(1,4)=2 then the A(1,4)=1 and A(1,5)=1. However this requires that A(1,5)=0 before being replaced with a 1.
if B(x,y)==1 && A(x,y-1)==0
A(x,y)=1
A(x,y-1)=1
elseif B(x,y)==2 && A(x,y+1)==0
A(x,y)=1
A(x,y+1)=1
elseif B(x,y)==3 && A(x+1,y)==0
A(x,y)=1
A(x+1,y)=1
elseif B(x,y)==4 && A(x-1,y)==0
A(x,y)=1
A(x-1,y)=1
end
this is the code I currently have however whenever I run it it only replaces values in the y+1 direction and none of the others. Am I writing this correctly? Is their a better way to write this? Any help would be greatly appreciated thank you!

Best Answer

so the E and W directions work but for some reason I can't get the N and S directions to work at all
As far as I can tell the code you've posted is bound to error at some point as it will inevitably try to index at 0 or past the size M.
First, three essential pieces of advice:
  • Do not use scripts called by scripts. It's a recipe for bug. It makes it very hard to track where the variables used by a subscript come from and it's very easy for a script to accidentally stomp on a variable used by another script. Learn to use functions properly.
  • Make sure to use meaningful names for your variables. As Image Analyst and I said, your x and y variables are misleading. x is traditionally seen as the horizontal direction which is the 2nd dimension in matlab. So row, column would be better variable names in your case.
  • Learn to use the debugger. When something doesn't work, step through your code one line at a time with the debugger and see if what happened is what you expected. It's the fastest way to find out what is wrong with your code.
There are plenty of problems with your code. Some minors, others major.
C(x,y)=NumberGenerator;
For once, you're calling a function, not a script. In some ways it is good you're calling a function, except that this function is badly written. The function:
function [r]=RandomNumber(z)
zmin=0;
zmax=1;
N=1;
r=zmin+rand(1,N)*(zmax-zmin);
end
The name of the function RandomNumber does not match the name of the file. Matlab will put a wiggly line under the function to warn you of that. The function name that matlab use will always be the file name, so the RandomNumber name is ignored. The function takes an input but never does anything with it. Just as well, since you didn't pass an input when you called the function. The function seems to be designed to return a variable size array of random number between arbitrary boundaries but since everything is hardcoded, it's simply a wrapper for rand. In effect the initial line is just:
C(x,y) = rand;
A useful version of that function could have been:
function r = NumberGenerator(N, zmin, zmax)
if nargin < 2 %no zmin and zmax passed, use default 0 and 1
zmin = 0;
zmax = 1;
end
if nargin < 1 %no N passed
N = 1
end
r = zmin + rand(1, N)*(zmax-zmin);
end
Continuing:
if C(x,y)<.2
%...








elseif C(x,y)>0
%...
If C is les than 0.2, we take the first branch. When we arrive to the elseif, we're guaranteed that C >=0.2, so it's definitively greater than 0. The elseif is therfeore not needed and just misleading. This should have been written:
if C(x,y)<.2
%...
else %no need for other test
%...
Moving on, we're in the C>=0.2 branch, we have, in MatrixGenV2:
if C(x,y)<.2000
As said, we're in the branch where C is guaranteed to eb 0.2 or more so that test will never be true
elseif C(x,y)>.8
%...
elseif (.6>C(x,y))&&(C(x,y)>.4)
%...
elseif (.8>C(x,y))&&(C(x,y)>.6)
%...
elseif(.4>C(x,y))&&(C(x,y))>.2
%...
end
Problem here, since you use strict inequalities (>) everywhere, if C is exactly 0.2, 0.4, 0.6 or 0.8 none of the branch will ever be true. You need to use some >= on some conditions. However,the simplest is to scarp thewhole ot and replace it with:
D(x, y) = discretize(C(x,y), [0.2 0.4 0.6 0.8 1]) %return 1 for values >= 0.2 and < 0.4, 2 for >=0.4 and < 0.6, ... 4 for >=0.8 and <= 1
Next, the big problem in Collapse:
if D(x,y)==E && M(x,y+1)==0
%...
elseif D(x,y)==W && M(x,y-1)==0
%...
If y happens to be equal to n, y+1 is an invalid index. If y happens to be 1, y-1 is 0, which is also not valid. This is boudn to result in an error at some point.
To finish, it seems to me that there is a fundamental problem with your algorithm. You carry out until all M is filled, but to fill a location, it and one of its neighbour must be empty (and then both are filled). I can see a scenario where the holes in M are just single zeros surrounded on all sides. In that case, any(M==0, 'all') is true so you keep on looping, but you can never find a location to fill.
Also, the closer you come to a filled matrix, he more often your picked random location is going to be something already filled. It would be much better to always pick a random location among the ones not filled:
while any(M==0,'all')
unfilledlocations = find(M == 0)' %linear indices of unfilled location
randidx = randi(numel(unfilledlocations)); %pick one of them at random
[row, column] = ind2sub(size(M), unfilledlocations(randidx)); %convert to row,column (your badly named x and y)
%we're guaranteed that row, column is 0. However, it's not guaranteed that any neighbour is empty
end