rows, cols, tile = 5, 7, 3
source = [10 * r + c for r in range(rows) for c in range(cols)]
actual = [None] * (rows * cols)
writes = [0] * len(actual)

for r0 in range(0, rows, tile):
    for c0 in range(0, cols, tile):
        for r in range(r0, min(r0 + tile, rows)):
            for c in range(c0, min(c0 + tile, cols)):
                destination = c * rows + r
                actual[destination] = source[r * cols + c]
                writes[destination] += 1

expected = [source[r * cols + c]
            for c in range(cols) for r in range(rows)]
assert actual == expected
assert writes == [1] * len(actual)
print(f'transpose {rows}x{cols} -> {cols}x{rows}: correct')
print('last output row:', actual[-rows:])

for stride in [32, 33]:
    banks = [(lane * stride) % 32 for lane in range(32)]
    distinct = len(set(banks))
    print(f'shared row stride={stride}: unique banks={distinct}')
print('Bank-address model only; no hardware counters or timing.')
