Coupled-Cluster Class¶
Coupled-cluster (CC) theory is one of the most accurate and widely used quantum chemistry methods for describing electron correlation in molecular systems. It represents the many-electron wavefunction using an exponential ansatz:
where \(|\Phi_0\rangle\) is a reference determinant (typically Hartree-Fock), and \(\hat{T}\) is a cluster operator that generates excited determinants. The cluster operator is typically expanded as:
where \(\hat{T}_n\) generates \(n\)-fold excited determinants. For computational tractability, the cluster operator is usually truncated. For example, CCSD includes only single and double excitations (\(\hat{T} = \hat{T}_1 + \hat{T}_2\)).
The CC class provides a convenient interface for setting up and processing CC equations using SeQuant’s symbolic algebra engine. It supports various CC formulations, including traditional, unitary, and orbital-optimized ansätze.
Overview¶
The CC class can be used to derive:
Ground state amplitude equations
λ (de-excitation) amplitude equations
Equation-of-motion (EOM) CC equations for excited states
Response equations for properties and perturbations
Expressions are generated in spin-orbital basis and can be post-processed using SeQuant’s spin-tracing capabilities. See Spin Tracing of Expressions for more details.
Ansatz Options¶
The CC class supports several CC ansätze through the CC::Ansatz enum:
Ansatz::T: Traditional CC ansatz, where the wavefunction is represented as \(|\Psi_{\text{CC}}\rangle = e^{\hat{T}}|\Phi_0\rangle\). This is the standard approach used in most implementations.Ansatz::oT: Orbital-optimized traditional ansatz. Singles amplitudes (\(\hat{T}_1\)) are excluded from the cluster operator, with orbital optimization performed instead.Ansatz::U: Unitary CC ansatz, where the wavefunction is represented as \(|\Psi_{\text{UCC}}\rangle = e^{\hat{T} - \hat{T}^\dagger}|\Phi_0\rangle\). Particularly useful for quantum computing applications.Ansatz::oU: Orbital-optimized unitary ansatz, combines both unitary and orbital optimized ansätze.
Key Methods¶
Lie Similarity Transformation¶
ExprPtr lst(ExprPtr A, ExprPtr B, size_t r);
Returns Lie similarity transformation, \(\bar{A} = e^{-\hat{B}} \hat{A} e^{\hat{B}}\), as a series of nested commutators, \([\hat{A},\hat{B}]\), \([[\hat{A},\hat{B}],\hat{B}]\), etc., up to order r.
Ground State Amplitudes¶
std::vector<ExprPtr> t(size_t commutator_rank = 4,
size_t pmax = std::numeric_limits<size_t>::max(),
size_t pmin = 0);
Derives the equations for the \(t\) amplitudes (\(\langle \Phi_P|\bar{H}|\Phi_0 \rangle = 0\)) up to specified excitation levels.
std::vector<ExprPtr> λ(size_t commutator_rank = 4);
Derives the equations for the \(\lambda\) de-excitation amplitudes.
Coupled-Cluster Response¶
std::vector<ExprPtr> t_pt(size_t order = 1, size_t rank = 1);
std::vector<ExprPtr> λ_pt(size_t order = 1, size_t rank = 1);
Derives perturbed amplitude equations for response theory calculations.
Equation-of-Motion Coupled-Cluster¶
std::vector<ExprPtr> eom_r(nₚ np, nₕ nh);
std::vector<ExprPtr> eom_l(nₚ np, nₕ nh);
Derives equation-of-motion coupled-cluster (EOM-CC) equations for excited states. The eom_r method generates equations for the right eigenvectors, while eom_l generates equations for the left eigenvectors.
Examples¶
The following examples demonstrate how to use the CC class to derive CC equations for various ansätze and excitation levels.
From this point onward, assume the following namespaces are imported, and the sequant::Context is configured as shown.
using namespace sequant;
using namespace sequant::mbpt;
set_default_context({.index_space_registry_shared_ptr = make_min_sr_spaces(),
.vacuum = Vacuum::SingleProduct});
Ground State CC Amplitude Equations¶
// Traditional CCSD
auto t_eqs = CC{2}.t();
std::wcout << "T1: " << to_latex(t_eqs[1]) << "\n"
<< "T2: " << to_latex(t_eqs[2]) << "\n";
// Lambda equations
auto l_eqs = CC{2}.λ();
std::wcout << "λ1: " << to_latex(l_eqs[1]) << "\n"
<< "λ2: " << to_latex(l_eqs[2]) << "\n";
// Unitary CCSD
auto Ut_eqs =
CC{2, CC::Ansatz::U}.t(4); // Use 4th-order commutator expansion
std::wcout << "T1 (UCC): " << to_latex(Ut_eqs[1]) << "\n"
<< "T2 (UCC): " << to_latex(Ut_eqs[2]) << "\n";
// Orbital-optimized CCSD
auto oT_eqs = CC{2, CC::Ansatz::oT}.t();
std::wcout << "T2 (oT): " << to_latex(oT_eqs[2]) << "\n";
EOM-CC Equations¶
// EE-EOM-CCSD (excitation energy)
auto r_eqs = CC{2}.eom_r(nₚ(2), nₕ(2));
std::wcout << "R1: " << to_latex(r_eqs[1]) << "\n"
<< "R2: " << to_latex(r_eqs[2]) << "\n";
// EE-EOM-CCSD Left eigenvectors
auto ee_l_eqs = CC{2}.eom_l(nₚ(2), nₕ(2));
std::wcout << "L1: " << to_latex(l_eqs[1]) << "\n"
<< "L2: " << to_latex(l_eqs[2]) << "\n";
// IP-EOM-CCSD (ionization potential)
auto ip_eqs = CC{2}.eom_r(nₚ(0), nₕ(1));
std::wcout << "IP-R1: " << to_latex(ip_eqs[0]) << "\n";
// EA-EOM-CCSD (electron attachment)
auto ea_eqs = CC{2}.eom_r(nₚ(1), nₕ(0));
std::wcout << "EA-R1: " << to_latex(ea_eqs[0]) << "\n";
Response and Perturbation Equations¶
// First-order perturbed amplitude equations
auto t_pt = CC{2}.t_pt(1, 1);
std::wcout << "T1 perturbed: " << to_latex(t_pt[1]) << "\n"
<< "T2 perturbed: " << to_latex(t_pt[2]) << "\n";
// First-order perturbed Lambda amplitude equations
auto l_pt = CC{2}.λ_pt(1, 1);
std::wcout << "λ1 perturbed: " << to_latex(l_pt[1]) << "\n"
<< "λ2 perturbed: " << to_latex(l_pt[2]) << "\n";
Advanced Usage¶
Truncating the Commutator Expansion¶
For traditional CC with two-body Hamiltonians, the commutator expansion is truncated at the a 4th-order. However, for unitary CC or other Hamiltonians, you may need to explicitly set the commutator rank:
// Unitary CCSDT with 6th-order commutator expansion
auto Ut_ccsdt = CC{3, CC::Ansatz::U}.t(6);
Spin Tracing of Expressions¶
Equations generated by the CC class are in spin-orbital basis. SeQuant also provides capability to transform these equations into spin-traced forms.
Make sure to include the <SeQuant/domain/mbpt/spin.hpp> header to access spin-tracing functions.
// Generate CCSD R2 equation
auto ccsd_eqs = CC{2}.t();
auto t2_eq = t_eqs[2];
// Convert to the closed-shell spin-traced form
auto t2_cs = closed_shell_CC_spintrace(t2_eq);
std::wcout << "Closed-shell spin-traced CCSD-R2: " << to_latex(t2_cs) << "\n";
// Convert to the open-shell spin-traced form
auto t2_os = open_shell_CC_spintrace(
t2_eq); // vector of expressions: {ɑɑ, ɑβ, ββ} blocks
std::wcout << "Open-shell spin-traced CCSD-R2:\n";
for (const auto& eq : t2_os) {
std::wcout << to_latex(eq) << "\n";
}