ffsim.linalg.double_factorized_t2_alpha_beta

ffsim.linalg.double_factorized_t2_alpha_beta(t2_amplitudes, *, tol=1e-08, max_terms=None)[source]

Double-factorized decomposition of alpha-beta \(t_2\) amplitudes.

Decompose alpha-beta \(t_2\) amplitudes into diagonal Coulomb matrices with orbital rotations. This function returns two arrays:

  • diagonal_coulomb_mats, with shape (n_terms, 3, norb, norb).

  • orbital_rotations, with shape (n_terms, 2, norb, norb).

The value of n_terms depends on the error tolerance tol. A larger error tolerance might yield a smaller value for n_terms. You can also set an optional upper bound on n_terms using the max_terms argument. To further optimize the resulting tensors to reduce the error in the factorization, pass the untruncated factorization to double_factorized_t2_alpha_beta_compressed().

The original \(t_2\) amplitudes tensor can be reconstructed, up to the error tolerance, using the following function:

def reconstruct_t2_alpha_beta(
    diag_coulomb_mats: np.ndarray,
    orbital_rotations: np.ndarray,
    norb: int,
    nocc_a: int,
    nocc_b: int,
) -> np.ndarray:
    n_terms = diag_coulomb_mats.shape[0]
    expanded_diag_coulomb_mats = np.zeros((n_terms, 2 * norb, 2 * norb))
    expanded_orbital_rotations = np.zeros(
        (n_terms, 2 * norb, 2 * norb), dtype=complex
    )
    for k in range(n_terms):
        (mat_aa, mat_ab, mat_bb) = diag_coulomb_mats[k]
        expanded_diag_coulomb_mats[k] = np.block(
            [[mat_aa, mat_ab], [mat_ab.T, mat_bb]]
        )
        orbital_rotation_a, orbital_rotation_b = orbital_rotations[k]
        expanded_orbital_rotations[k] = scipy.linalg.block_diag(
            orbital_rotation_a, orbital_rotation_b
        )
    return (
        1j
        * np.einsum(
            "kpq,kap,kip,kbq,kjq->ijab",
            expanded_diag_coulomb_mats,
            expanded_orbital_rotations,
            expanded_orbital_rotations.conj(),
            expanded_orbital_rotations,
            expanded_orbital_rotations.conj(),
        )[:nocc_a, norb : norb + nocc_b, nocc_a:norb, norb + nocc_b :]
    )

Note: Currently, only real-valued \(t_2\) amplitudes are supported.

Parameters:
  • t2_amplitudes (ndarray) – The doubles amplitudes tensor of shape (nocc_a, nocc_b, nvrt_a, nvrt_b), where nocc_a is the number of occupied spin-alpha orbitals, nvrt_a is the number of virtual spin-alpha orbitals, nocc_b is the number of occupied spin-beta orbitals, and nvrt_b is the number of virtual spin-beta orbitals.

  • tol (float) – Tolerance for error in the decomposition. The error is defined as the maximum absolute difference between an element of the original tensor and the corresponding element of the reconstructed tensor.

  • max_terms (int | None) – An optional limit on the number of terms to keep in the decomposition of the \(t_2\) amplitudes tensor. This argument overrides tol.

Return type:

tuple[ndarray, ndarray]

Returns:

  • The diagonal Coulomb matrices, as a Numpy array of shape (n_terms, 3, norb, norb). The last two axes index the rows and columns of the matrices, and the third from last axis, which has 3 dimensions, indexes the spin interaction type of the matrix: alpha-alpha, alpha-beta, and beta-beta (in that order). The first axis indexes the terms of the decomposition.

  • The orbital rotations, as a Numpy array of shape (n_terms, 2, norb, norb). The last two axes index the rows and columns of the orbital rotations, and the third from last axis, which has 2 dimensions, indexes the spin sector of the orbital rotation: first alpha, then beta. The first axis indexes the terms of the decomposition.

Raises: