opt-einsum
opt-einsum is a Python library that optimizes the contraction order of Einstein summation expressions, significantly reducing the execution time of einsum-like operations in various backends such as NumPy, Dask, PyTorch, TensorFlow, and JAX. It achieves this by finding efficient contraction paths, often dispatching operations to highly optimized routines like BLAS or cuBLAS. The library is currently at version 3.4.0 and is actively maintained, serving as the underlying optimization engine for `numpy.einsum(..., optimize=True)` and `torch.einsum` when installed.
Warnings
- breaking The `path` keyword argument in `opt_einsum.contract` has been changed to `optimize` to align more closely with NumPy's API. The `path` keyword will be deprecated in future versions.
- gotcha When using `numpy.einsum`, explicitly setting `optimize=True` (or a specific path strategy) is crucial for performance. Without `optimize`, `numpy.einsum` defaults to a left-to-right contraction order, which can be highly inefficient for complex expressions. `opt-einsum.contract` applies optimization by default.
- gotcha Finding the truly optimal contraction path for an einsum expression is an NP-hard problem. While `opt-einsum` offers an 'optimal' strategy, it can scale factorially with the number of terms and quickly become intractable for many tensors. For larger expressions, heuristic algorithms like 'greedy' or 'random-greedy' are used.
- gotcha The `memory_limit` parameter in `opt_einsum.contract` can constrain the size of intermediate tensors. While useful for memory management, imposing a limit can make contractions exponentially slower to perform if it restricts the optimizer from finding the most efficient path. The default is `None`, meaning no memory limit.
Install
-
pip install opt-einsum
Imports
- contract
from opt_einsum import contract
- contract_path
from opt_einsum import contract_path
Quickstart
import numpy as np
from opt_einsum import contract
N = 10
C = np.random.rand(N, N)
I = np.random.rand(N, N, N, N)
# Using unoptimized numpy.einsum (for comparison)
# result_np = np.einsum('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C)
# Using opt_einsum.contract for optimized performance
result_opt = contract('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C)
print(f"Optimized result shape: {result_opt.shape}")