Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
## 2025-11-01 - [Avoid Temporary Array Allocations in Reductions]
**Learning:** In loops over parameters like temperature (`thermal_scan`), doing `np.sum(arr1 * arr2)` where array sizes match the system Hilbert space creates huge temporary arrays per loop iteration. Memory allocation dominates execution time.
**Action:** Use `np.dot(arr1, arr2)` instead of `np.sum(arr1 * arr2)` for 1D arrays to evaluate reductions in C-level BLAS/NumPy functions, bypassing Python/NumPy array allocations and boosting performance significantly with less peak memory.

## 2025-11-01 - [Schmidt Decomposition Optimization]
**Learning:** When calculating the Schmidt spectrum (singular values) without needing the singular vectors (`return_vecs=False`), using `scipy.linalg.svdvals(A)` is suboptimal, particularly for highly rectangular matrices. Computing the smaller reduced density matrix ($A A^\dagger$ or $A^\dagger A$) and finding its eigenvalues with `np.linalg.eigvalsh` can be 2x to 6x faster.
**Action:** Replace `la.svdvals(A)` with `np.linalg.eigvalsh` on the smaller density matrix dimension (`dA` vs `dB`). Ensure the values are correctly clipped `[0, 1]` and sorted in descending order to match the original output format.
18 changes: 15 additions & 3 deletions physics/density_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,9 +434,21 @@ def schmidt(
u, s, vh = la.svd(psi_mat, full_matrices=False)
return s**2 if square else s, (u, vh), psi_mat
else:
# For values only, use more efficient SVD call (no full decomposition)
s = la.svdvals(psi_mat)
return s**2 if square else s
# For values only, it is significantly faster to compute the smaller RDM
# and find its eigenvalues rather than calling svdvals, especially for
# highly rectangular matrices (e.g., small subsystems).
dA, dB = psi_mat.shape
if dA <= dB:
rho_small = psi_mat @ psi_mat.conj().T
else:
rho_small = psi_mat.conj().T @ psi_mat

Comment on lines +437 to +445
w = np.linalg.eigvalsh(rho_small)
w = np.clip(w, 0.0, 1.0)
Comment on lines +446 to +447

# Sort descending to match svdvals behavior exactly
w = np.sort(w)[::-1]
return w if square else np.sqrt(w)
else:
rho_A = rho(state, va, ns, local_dim, contiguous, fermionic=fermionic)
if return_vecs:
Expand Down