$A^{p+1}_{ij}$: $$A^p_{ij} = Q^p_{ij} R^p_{ij} = \left( Q^p_{ij} U^p_{ij} \Sigma^p_{ij} \right) {V^p_{ij}}^T = A^{p+1}_{ij} {V^p_{ij}}^T.$$ If the right singular vectors are needed, we can accumulate the action of $V^p_{ij}$ on the identity matrix. For our batched implementation, we use the batch QR routine developed in Section \[sec:batch\_qr\] and `gemm` routines from MAGMA to multiply the orthogonal factor by the left singular vectors, while the SVD is computed by our shared memory batched kernel. The same convergence test used in the Gram matrix method can be used on the triangular factor, since the triangular factor should be close to a diagonal matrix if a pair of block columns are orthogonal. This gives us the direct path of the batched block Jacobi Algorithm \[alg:block\_jacobi\] to compute the SVD of a batch of matrices in global memory.

\[t\]

$e_l = 0$ $G = \text{batchSyrk}(A_{ij})$ $[A_{ij}, G] = \text{batchQR}(A_{ij})$ $e_l = \text{max}(e_l, \text{scaledOffdiag}(G))$ $U = \text{batchSvd}(G)$ $A_{ij} = \text{batchGemm}(A_{ij}, U)$ $e = \text{max}(e_l)$

Performance {#performance-2}
-----------

Figures \[fig:block\_jacobi\_profile1\] and \[fig:block\_jacobi\_profile1\] show the profiling of the different computational kernels involved in the batched block algorithms with a block width of $32$, specifically percentages of total execution time for determining convergence and memory operations, matrix multiplications, 