private void TransposeAndSwap(ref SubmatrixDims a, ref SubmatrixDims b) { Debug.Assert(a.Width == b.Height && a.Height == b.Width); // 1. Prepare the submatrices SubmatrixDims a11, a21, a12, a22; SubmatrixDims b11, b21, b12, b22; a.SplitDims(out a11, out a21, out a12, out a22); b.SplitDims(out b11, out b21, out b12, out b22); // 2. If the matrices are small, transpose them naively // Check just the first one; because we have a square matrix, the other sizes should be very similar if (a11.Width * a11.Height < NaiveThreshold) { TransposeAndSwapNaive(ref a11, ref b11); TransposeAndSwapNaive(ref a21, ref b12); TransposeAndSwapNaive(ref a12, ref b21); TransposeAndSwapNaive(ref a22, ref b22); return; } // 3. Transpose and swap them TransposeAndSwap(ref a11, ref b11); TransposeAndSwap(ref a21, ref b12); TransposeAndSwap(ref a12, ref b21); TransposeAndSwap(ref a22, ref b22); }
// The recursion ends when the split submatrices are small enough. This saves us // a lot of work caused by recursion. We do the recursion end check before recursing // instead of at the start of the recursive func to reduce the recursion depth by one // (it can further save us a lot of recursive calls -- with the tree branching // factor of ~4 the number of leaves in the recursion tree is very high compared to // the number of internal nodes. private void TransposeInternal(ref SubmatrixDims dims) { // 1. Prepare the submatrices SubmatrixDims a11, a21, a12, a22; dims.SplitDims(out a11, out a21, out a12, out a22); // 2. If the matrices are small enough, transpose them naively if (a11.Width * a11.Height <= NaiveThreshold) { TransposeInternalNaive(ref a11); TransposeInternalNaive(ref a22); TransposeAndSwapNaive(ref a21, ref a12); return; } // 3. Recurse on the submatrices TransposeInternal(ref a11); TransposeInternal(ref a22); TransposeAndSwap(ref a21, ref a12); }