Einsum and Tensor Contraction
A compact notation, einsum, for expressing sums, dot products, matrix multiplies and higher-dimensional tensor operations with one consistent syntax instead of a different function call for each shape.
Prerequisites: Vectorization vs Loops
A quant research codebase is full of operations on arrays with more than two dimensions — a batch of covariance matrices, a panel of factor loadings across time and stocks, a tensor of Greeks by strike, tenor and scenario. Writing each of these as a chain of reshape, transpose and matmul calls gets unreadable fast, and it's easy to silently multiply along the wrong axis. Einsum (Einstein summation notation) gives you one syntax for all of these: you name the axes of each input array with letters, name the axes you want in the output, and any letter that disappears between input and output is summed over.
For example, np.einsum('ij,jk->ik', A, B) means: take axis of and axis of , multiply elementwise, and sum over — which is exactly ordinary matrix multiplication. np.einsum('ii->', A) sums the diagonal, i.e. the trace. np.einsum('bij,bjk->bik', A, B) does the same matrix multiply independently for every entry in a batch — a batched matrix product in one line, with no manual loop over .
Worked example. Suppose you have R, a (1000, 50) array of daily returns for 1000 days and 50 stocks, and you want the (50, 50) covariance-like matrix R.T @ R. Written as einsum: np.einsum('ti,tj->ij', R, R) — sum over the time axis , keep stock axes and . This is identical to R.T @ R for a plain matrix product, but the same pattern extends unchanged to a batched version, np.einsum('bti,btj->bij', R, R), computing 1000 covariance matrices at once for b separate portfolios — something that would otherwise need an explicit Python loop or a much less readable reshape-and-matmul chain.
Einsum names each array's axes with letters and sums over any letter that is repeated across inputs but absent from the output — it unifies dot products, matrix multiplication, batched multiplication and trace under one notation, and is often faster than the equivalent chain of reshapes because the underlying library can choose the best contraction order.
Related concepts
Practice in interviews
Further reading
- Numpy documentation, np.einsum