Quant Memo
Core

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 jj of AA and axis jj of BB, multiply elementwise, and sum over jj — 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 bb in a batch — a batched matrix product in one line, with no manual loop over bb.

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 tt, keep stock axes ii and jj. 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
ShareTwitterLinkedIn