For the most part, LAPACK represents unitary matrices like $\mathbf U$ as products of householder reflectors, and provides specialized routines to work with that representation (for instance, use [dormqr] to multiply by $\mathbf U$, or [dorgqr] to explicitly tabulate $\mathbf U$ into a dense matrix).
If you already have $\mathbf U$ in householder format, it would be more idiomatic to use [dormqr] to update A, instead of [dgemm]. In particular, two calls to [dormqr] can update $\mathbf B = \mathbf U^T \mathbf A \mathbf U$ in place (overwriting $\mathbf A$ with $\mathbf B$), while [dgemm] will require a temporary matrix. This point might be somewhat academic, though, as [dormqr] requires additional workspace while [dgemm] does not. Although there is a workspace-free routine [dorm2r] that performs a similar function as [dormqr], it's not recommended because it's a BLAS2 algorithm and won't be as fast.
I suppose if I already was just given $\mathbf U$ explicitly tabulated, I'd probably just stick with [dgemm]. But if you have control over how $\mathbf U$ is generated/computed (for instance, some hand-rolled gram-schmidt procedure applied to some other basis set), I'd strongly consider refactoring everything to use the LAPACK tooling instead (that is use [dgeqrf] to orthogonalize your basis into $\mathbf U$ and then use [dormqr] to apply it, there might not be any need to ever form it explicitly).
Out of curiousity, what do you do with $\mathbf B$ once you have it? There might be more refactoring/optimization opportunities if you can share more about the larger process.
mkl_sparse_sypr
(ormkl_sparse_?_syprd
if you want a dense result) that performs the product $U^T A U$, where $A$ must be a symmetric matrix, and returns the upper triangular portion of the result. This is way faster than any combination of routines that I have tested. Unfortunately, I haven't seen this in any other linear algebra libraries. $\endgroup$mkl_sparse_?_syprd
takes a dense $U$. Your $A$ is essentially ~50% sparse, so I think its worth a shot. I have tried @vibe 's approach as well:DSYRK
performs the operation $B^T B$, where in your case $B = L^T U$. I foundsyprd
to be faster (your experience may be different!) $\endgroup$TRMM
, oneDGEMM
, and some addition (you only need to compute your preferred triangle, as the result is symmetric). Not sure if this is better in practice as I have never tried it. I have a feeling Intel does something like this because they don't require $A$ to be positive definite (hence no internal cholesky). $\endgroup$