Matrix Value Replacement Problem

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!

10 个评论

Presumably, these tests are inside one or more loops. Possibly, the problem is with the loops. Certainly, we'd need to know what the (badly named) x and y are.
In your above example, what is the result that should be produced? Most likely, no loop is needed.
x and y is meant to just be the rows and columns in the matrix. they are chosen randomly using the randi function
n=5 %matrix size
x=randi(n)
y=randi(n)
yes this does take place within another loop. heres an example of what I'm looking for with a 2x2 matrix based on the previous code
for A= 0 0
0 1
B= 0 0
0 2
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
Does your x and y selection take place within a loop? Because if not then you're only looking at one set of values for x and y, so you can only make one set of changes.
yes it does take place in a loop
So, you expressely want to do the replacement one element at a time at a random location, not remplace all valid positions all in one go?
It doesn't look like there's anything wrong with your tests, so if the code doesn't work it's with something else that you're not showing, so give us the whole code.
Note that x usually denotes the horizontal direction, the columns, not the rows. I would recommend you rename your variables row, column to avoid ambiguity (or r, c at a push)
This is the 'Test' function
n=5; %matrix size
M=zeros(n);%matrix of all zeros that is being updated
C=zeros(size(M));%matrix of random numbers that determine the directional value assigned to each position
D=zeros(size(M));%matrix of positional values
counter=0;
while any(M==0,'all')
counter=counter+1;
y=randi(n);
x=randi(n);
if M(x,y)==0
C(x,y)=NumberGenerator; %determines what random value is assigned to the matrix postion
if C(x,y)<.2
M(x,y)=0;
D(x,y)=0;
elseif C(x,y)>0
M(x,y)=1;
MatrixGenV2; %subroutine that generates a directional value at each position based on C(x,y)
Collapse; %subroutine that determines collapse
BoundaryCondition; %Boundary condition I've placed on the matrix
end
end
end
'Boundary Condition'
%creates a periodic boundary condition to imitate experimental conditions
if y==1 && D(x,y)==W
M(x,n)=1
M(x,1)=1
elseif y==n && D(x,y)==E
M(x,1)=1
M(x,n)=1
end
if x==1 && D(x,y)==N
M(n,y)=1
M(1,y)=1
elseif x==n && D(x,y)==S
M(1,y)=1
M(n,y)=1
end
'MatrixGenV2'
%Generates a Directional Matrix assigned to each collapsed value in M(ii)
W=1;%indicates collapsed molecule in West direction
S=2;%indicates collapsed molecule in South direction
N=3;%indicates collapsed molecule in North direction
E=4;%indicates collapsed molecule in East direction
if C(x,y)<.2000
D(x,y)=0;
elseif C(x,y)>.8
D(x,y)=E;
elseif (.6>C(x,y))&&(C(x,y)>.4)
D(x,y)= W;
elseif (.8>C(x,y))&&(C(x,y)>.6)
D(x,y)= S;
elseif(.4>C(x,y))&&(C(x,y))>.2
D(x,y)= N;
end
'NumberGenerator'
%generates a random number
function [r]=RandomNumber(z)
zmin=0;
zmax=1;
N=1;
r=zmin+rand(1,N)*(zmax-zmin);
end
'Collapse'
if D(x,y)==E && M(x,y+1)==0
M(x,y)=2;
M(x,y+1)=2;
elseif D(x,y)==W && M(x,y-1)==0
M(x,y)=2;
M(x,y-1)=2;
elseif D(x,y)==N && M(x+1,y)==0
M(x,y)=2;
M(x+1,y)=2;
elseif D(x,y)==S && M(x-1,y)==0
M(x,y)=2;
M(x-1,y)=2;
end
I'll have a look later on in details at your code. In the meantime, I would strongly recommend that you change the way you code and use functions instead of scripts called from scripts as your current structure is going to make it very difficult to debug and maintain very quickly.
E.g. Collapse should be written as:
function M = collapse(M, D, x, y)
W=1; S=2; N=3; E=4; %or make D a categorical array
if D(x,y)==E && M(x,y+1)==0
M(x,y)=2;
M(x,y+1)=2;
elseif D(x,y)==W && M(x,y-1)==0
M(x,y)=2;
M(x,y-1)=2;
elseif D(x,y)==N && M(x+1,y)==0
M(x,y)=2;
M(x+1,y)=2;
elseif D(x,y)==S && M(x-1,y)==0
M(x,y)=2;
M(x-1,y)=2;
end
end
and called appropriately
hello again have you had any chance too revisit my code?
Why are you choosing the first index as x, and the second one as y???
You should know that arrays are indexed as (y, x), NOT (x, y).
See if that fixes your problem.
so the E and W directions work but for some reason I can't get the N and S directions to work at all

请先登录,再进行评论。

 采纳的回答

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

更多回答(0 个)

类别

帮助中心File Exchange 中查找有关 Cell Arrays 的更多信息

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by