emphasized textIt is possible to find a rectangle in a large n by n matrix of integers that has the maximum sum reasonably quickly. There is an O(n^3) time algorithm as described here and here for example. There is also fast code.
import numpy as npimport timeimport numbanumba.config.DISABLE_JIT = Falsedef _gt(s=0.0): return time.perf_counter() - s@numba.njit(cache=True)def kadane(arr, n): # initialize subarray_sum, max_subarray_sum and subarray_sum = 0 max_subarray_sum = np.int32(-2147483648) # Just some initial value to check # for all negative values case finish = -1 # local variable local_start = 0 for i in range(n): subarray_sum += arr[i] if subarray_sum < 0: subarray_sum = 0 local_start = i + 1 elif subarray_sum > max_subarray_sum: max_subarray_sum = subarray_sum start = local_start finish = i # There is at-least one # non-negative number if finish != -1: return max_subarray_sum, start, finish # raise AssertionError('Untested code block') # Special Case: When all numbers # in arr[] are negative max_subarray_sum = arr[0] start = finish = 0 # Find the maximum element in array for i in range(1, n): if arr[i] > max_subarray_sum: max_subarray_sum = arr[i] start = finish = i return max_subarray_sum, start, finish# The main function that finds maximum subarray_sum rectangle in M@numba.njit(cache=True, parallel=True)def findMaxsubarray_sum(M): num_rows, num_cols = M.shape out_pos_arr = np.empty((num_cols * num_cols, 4), dtype=np.int32) out_sum_arr = np.full((num_cols * num_cols,), np.int32(-2147483648), dtype=np.int32) # Set the left column for left in numba.prange(num_cols): # Initialize all elements of temp as 0 temp = np.zeros(num_rows, dtype=np.int_) # Set the right column for the left # column set by outer loop for right in range(left, num_cols): temp += M[:num_rows, right] subarray_sum, start, finish = kadane(temp, num_rows) out_sum_arr[left * num_cols + right] = subarray_sum out_pos_arr[left * num_cols + right, :] = np.array((left, right, start, finish)) max_pos = np.argmax(out_sum_arr) finalLeft, finalRight, finalTop, finalBottom = out_pos_arr[max_pos] max_subarray_sum = out_sum_arr[max_pos] return finalTop, finalLeft, finalBottom, finalRight, max_subarray_sumdef _main(): # First loop may have numba compilations # second loop shows true-er performance run_sum = 0.0 loop_count = 10 for i in range(loop_count): rng = np.random.default_rng(seed=42) N = 800 # N = 1700 square = rng.integers(-3, 4, (N, N), dtype=np.int32) # square = rng.integers(-30, -4, (N, N)) s = _gt() finalTop, finalLeft, finalBottom, finalRight, max_subarray_sum = findMaxsubarray_sum(square) run_time = _gt(s) print(f'Run time: {N},{run_time:8.6f}') # Don't count numba compilation time if i > 0: run_sum += run_time if False: print("(Top, Left)", "(", finalTop, finalLeft, ")") print("(Bottom, Right)", "(", finalBottom, finalRight, ")") print("Max subarray_sum is:", max_subarray_sum) print() print(f'Average speed: {run_sum / (loop_count - 1):.5f}')if __name__ == '__main__': _main()
I would like to find a pair of rectangles where the sum of the integers covered is maximal. Double counting is not allowed (that is an integer at a given coordinate is only counted once). I am happy if we restrict the problem to non-overlapping rectangles if it makes it easier to do quickly.
How can you do that?