Given a matrix A of dimension MxN (4x4), how would one find the next-best minimum of each 2x2 submatrix?
A = array([[ 32673. , 15108.2 , 26767.2 , 9420. ],
[ 32944.2 , 14604.01 , 26757.01 , 9127.2 ],
[ 26551.2 , 9257.01 , 26595.01 , 9309.2 ],
[ 26624. , 8935.2 , 26673.2 , 8982. ]])
The next-best minimum of a set of submatrixes, is the minimum of that submatrix that does not conflict with the local position of other minima:
Example Algorithm:
1. Find the minimum in A: 8935.2 global coords[3,1], local coords [1,1]
2. No other matrix has been evaluated so no conflict yet.
3. Find the next submatrix min: 8982. gc [3,3], lc [1,1]
4. Conflict exists, find next min in same submatrix: 9309.2 gc [2,3], lc [0,1]
5. Find next submatrix min: 9420 gc [0,3] lc[0,1]
6. Conflict exists, find next min: 26757.01 gc [1,2] lc [1,0]
7. Find next submatrix min: 14604 -- conflict with lc[1,1]
8. Find next submatrix min: 15108.2 -- conflict with lc [0,1]
9. Find next submatrix min: 32673. gc [0,0], lc [0,0]
one approach I have thought of trying is to follow the algorithm above, but instead of exhaustively searching each submatrix again, I globally update each submatrix local position with a 'high' value (>> max(A)), which is incremented on each successful find of a minima.
The expected output would be a list:
[((0, 0), (0, 0), 32673), ((0, 1), (1, 0), 26757.01), ((1, 0), (1, 1), 8935.2), ((1, 1), (0, 1), 9309.2)]
of the form [((t1), (t2), value) ... ], where t1 is the coordinates of the submatrix in A, and t2 is the coordinates of the selected minimum in the submatrix.
Edit: the submatrices are defined as ZxZ, where MxN modulo ZxZ == 0, and are non-overlapping starting at (0,0), and tiled to match the dimensions of MxN.
Edit: Below is a solution I've constructed, but it is slow. I suspect that that if I delete submatrices from the matrix on each iteration, then the performance might be improved, but I am not sure how to do this.
def get_mins(self, result):
# result is the 2d array
dim = 2 # 2x2 submatrix
mins = []
count = 0
while count < dim**2:
a, b = result.shape
M4D = result.reshape(a//dim, dim, b//dim, dim)
lidx = M4D.transpose(0, 2, 1, 3).reshape(-1, b//dim, dim**2).argmin(-1)
r, c = numpy.unravel_index(lidx, [dim, dim])
yy = M4D.min(axis=(1, 3))
ww = numpy.dstack((r, c))
super_min = numpy.unravel_index(numpy.argmin(yy), (dim, dim))
rows = super_min[0]
cols = super_min[1]
# ww[rows,cols] g_ves us 2x2 position
offset_r, offset_c = ww[rows, cols]
# super_min gives us submatrix position
mins.append((tuple(super_min), (offset_r, offset_c), yy.min()))
if dim > 1:
# update all other positions with inf >> max(result)
result[numpy.ix_([offset_r + (d * dim) for d in range(dim)], [offset_c + (d * dim) for d in range(dim)])] = numpy.inf
# update the submatrix to all == numpy.inf
result[rows*dim:((rows*dim)+dim), cols*dim:((cols*dim)+dim)] = numpy.inf
count += 1
return mins