There are some bounds-checking bugs in your code:
- front(1, 1, IM, Lx, Ly) will crash.
- front(1, Lx, IM, Lx, Ly) will crash.
- front(Ly, 1, IM, Lx, Ly) will crash.
- front(Ly, Lx, IM, Lx, Ly) will crash.
In other words, "front" crashes on the corners of the grid.
Here is an alternative implementation of "front" that bounds-checks properly:
function [bin] = front(a, b, IM, Lx, Ly)
bin = 0;
y_coords = [a+1 a-1 a a ];
x_coords = [b b b+1 b-1];
for ii = 1:4
y = y_coords(ii);
x = x_coords(ii);
if y == 0 || y == Ly + 1 || x == 0 || x == Lx + 1
continue
end
if IM(y, x) == 1
bin = 1;
end
end
end
Furthermore,
- The line "bin = front(i-1,j, IM,Lx,Ly);" will crash whenever i == 1. You should make sure that i > 1 first.
- You keep clearing pfront, so once the program is done (no cells left to invade) it will crash. You should use "pfront = [];" to empty the array instead and then check if the array is empty before using it.
I also have a few suggestions / pointers:
- "e = find(pfront(:,1)==min(pfront(:,1)))" would be better written as "[~, e] = min(pfront(:, 1))" because the min function actually has two return values: the minimum value, and its index.
- nstop and tend seem like they are never used in the code you posted (tend is always 1, and nstop is always 0).
- Instead of "s = sort(IM(i,1:end)); if s(1)==1" you can write "if any(IM(i, :) == 1)".
Also, you have a bug in your algorithm. You keep adding cells that have already been invaded to pfront, preventing other cells from being invaded (because the already-invaded-cells have smaller probability so "[~, e] = min(pfront(:, 1))" will just select a cell that has already been invaded).
What you can do is iterate over the entire grid, and add each cell to your list of candidates (pfront) if it is A) part of the main defending cluster (check its IM label) and B) part of the front. B will be taken care of by the "front" function, so we just have to take care of A.
To see if a cell is part of the main defending cluster, we can verify that the defending cluster that it IS part of touches the edge of the grid. If we surround the grid in a border of defenders before calling bwlabel, it will consider all defending clusters that are adjacent to the border to be the same cluster, so all non-trapped clusters will have the same label. So if we do this:
IM = bwlabel(padarray(IM-1, [1 1], 1), 4) + 1;
not_trapped = IM(1, 1);
IM = IM(2:end-1, 2:end-1);
Then to verify A we just check "IM(i, j) == not_trapped".
With all that out of the way, we can make some modifications to get the behavior you're looking for. If you want multiple sources to grow simultaneously, you need to distinguish your pfront values by the connected component of invaders it is a part of. You could use an additional bwlabel to get the connected components of invaders, and add another component to each pfront entry that represents the source a cell is on the front of.
However, this introduces an additional complication. What if a cell is on the front of two different connected components at the same time? If we iterate as before, the "front" function will only tell us that a cell is on some front, but it won't tell us which front (or fronts) it's on, now that there are multiple fronts. We can modify the "front" function to return a list of fronts that a given cell is a part of:
function [bin] = front(a, b, source, Lx, Ly)
bin = [];
y_coords = [a+1 a-1 a a ];
x_coords = [b b b+1 b-1];
for ii = 1:4
y = y_coords(ii);
x = x_coords(ii);
if y == 0 || y == Ly + 1 || x == 0 || x == Lx + 1
continue
end
if source(y, x)
bin = [bin, source(y, x)];
end
end
end
And that "source" argument isn't IM anymore. Instead, source should be the result of a second bwlabel on invaders: "source = bwlabel(IM == 1)". Now adding a cell to the fronts that it is a part of looks like this:
if IM(i, j) == not_trapped
fronts = front(i, j, source, Lx, Ly);
for n = 1:numel(fronts)
pfront(k, 1) = fronts(n);
pfront(k, 2) = pt(i, j);
pfront(k, 3) = i;
pfront(k, 4) = j;
k = k+1;
end
end
And finally, the invasion step now looks like this (update the front of each source separately):
fronts = unique(pfront(:, 1));
for n = 1:numel(fronts)
candidates = pfront(pfront(:, 1) == fronts(n), 2:end);
[~, e] = min(candidates(:, 1));
IM(candidates(e, 2), candidates(e, 3)) = 1;
end