ffsim

ffsim is a software library for fast simulation of fermionic quantum circuits.

class ffsim.BitstringType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: Enum

Enumeration for indicating the data type of bitstrings.

String:

[“0101”, “0110”]

Integer:

[5, 6]

Bit array:
[[False, True, False, True],

[False, True, True, False]]

BIT_ARRAY = 3

Bit array.

INT = 2

Integer.

STRING = 1

String.

class ffsim.DiagonalCoulombHamiltonian(one_body_tensor, diag_coulomb_mats, constant=0.0)[source]

Bases: object

A diagonal Coulomb Hamiltonian.

A Hamiltonian of the form

\[H = \sum_{\sigma, pq} h_{pq} a^\dagger_{\sigma, p} a_{\sigma, q} + \frac12 \sum_{\sigma \tau, pq} V_{(\sigma \tau), pq} n_{\sigma, p} n_{\tau, q} + \text{constant}.\]

where \(n_{\sigma, p} = a_{\sigma, p}^\dagger a_{\sigma, p}\) is the number operator on orbital \(p\) with spin \(\sigma\).

Here \(h_{pq}\) is called the one-body tensor and \(V_{(\sigma \tau), pq}\) are called the diagonal Coulomb matrices. The brackets indicate that \(V_{(\sigma \tau)}\) is a circulant matrix, which satisfies \(V_{\alpha\alpha}=V_{\beta\beta}\) and \(V_{\alpha\beta}=V_{\beta\alpha}\).

one_body_tensor

The one-body tensor \(h\).

Type:

np.ndarray

diag_coulomb_mats

The diagonal Coulomb matrices \(V_{(\sigma \tau)}\), given as a pair of Numpy arrays specifying independent coefficients for alpha-alpha and alpha-beta interactions (in that order).

Type:

np.ndarray

constant

The constant.

Type:

float

static from_fermion_operator(op)[source]

Convert a FermionOperator to a DiagonalCoulombHamiltonian.

Return type:

DiagonalCoulombHamiltonian

property norb: int

The number of spatial orbitals.

class ffsim.DoubleFactorizedHamiltonian(one_body_tensor, diag_coulomb_mats, orbital_rotations, constant=0.0, z_representation=False)[source]

Bases: object

A Hamiltonian in the double-factorized representation.

The double-factorized form of the molecular Hamiltonian is

\[H = \sum_{\sigma, pq} \kappa_{pq} a^\dagger_{\sigma, p} a_{\sigma, q} + \frac12 \sum_t \sum_{\sigma\tau, ij} Z^{(t)}_{ij} n^{(t)}_{\sigma, i} n^{(t)}_{\tau, j} + \text{constant}'.\]

where

\[n^{(t)}_{\sigma, i} = \sum_{pq} U^{(t)}_{pi} a^\dagger_{\sigma, p} a_{\sigma, q} U^{(t)}_{qi}.\]

Here each \(U^{(t)}\) is a unitary matrix and each \(Z^{(t)}\) is a real symmetric matrix.

“Z” representation

The “Z” representation of the double factorization is an alternative representation that sometimes yields simpler quantum circuits.

Under the Jordan-Wigner transformation, the number operators take the form

\[n^{(t)}_{\sigma, i} = \frac{(1 - z^{(t)}_{\sigma, i})}{2}\]

where \(z^{(t)}_{\sigma, i}\) is the Pauli Z operator in the rotated basis. The “Z” representation is obtained by rewriting the two-body part in terms of these Pauli Z operators and updating the one-body term as appropriate:

\[H = \sum_{\sigma, pq} \kappa'_{pq} a^\dagger_{\sigma, p} a_{\sigma, q} + \frac18 \sum_t \sum_{\sigma\tau, ij}^* Z^{(t)}_{ij} z^{(t)}_{\sigma, i} z^{(t)}_{\tau, j} + \text{constant}''\]

where the asterisk denotes summation over indices \(\sigma\tau, ij\) where \(\sigma \neq \tau\) or \(i \neq j\).

References

one_body_tensor

The one-body tensor \(\kappa\).

Type:

np.ndarray

diag_coulomb_mats

The diagonal Coulomb matrices.

Type:

np.ndarray

orbital_rotations

The orbital rotations.

Type:

np.ndarray

constant

The constant.

Type:

float

z_representation

Whether the Hamiltonian is in the “Z” representation rather than the “number” representation.

Type:

bool

static from_molecular_hamiltonian(hamiltonian, *, z_representation=False, tol=1e-08, max_vecs=None, optimize=False, method='L-BFGS-B', callback=None, options=None, diag_coulomb_indices=None, cholesky=True)[source]

Initialize a DoubleFactorizedHamiltonian from a MolecularHamiltonian.

This function takes as input a MolecularHamiltonian, which stores a one-body tensor, two-body tensor, and constant. It performs a double-factorized decomposition of the two-body tensor and computes a new one-body tensor and constant, and returns a DoubleFactorizedHamiltonian storing the results.

See DoubleFactorizedHamiltonian for a description of the z_representation argument. See ffsim.linalg.double_factorized() for a description of the rest of the arguments.

Parameters:
  • hamiltonian (MolecularHamiltonian) – The Hamiltonian whose double-factorized representation to compute.

  • z_representation (bool) – Whether to use the “Z” representation of the decomposition.

  • 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_vecs (int | None) – An optional limit on the number of terms to keep in the decomposition of the two-body tensor. This argument overrides tol.

  • optimize (bool) – Whether to optimize the tensors returned by the decomposition.

  • method (str) – The optimization method. See the documentation of scipy.optimize.minimize for possible values.

  • callback – Callback function for the optimization. See the documentation of scipy.optimize.minimize for usage.

  • options (dict | None) – Options for the optimization. See the documentation of scipy.optimize.minimize for usage.

  • diag_coulomb_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the diagonal Coulomb matrices. Matrix entries corresponding to indices not in this list will be set to zero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error. This parameter is only used if optimize is set to True.

  • cholesky (bool) – Whether to perform the factorization using a modified Cholesky decomposition. If False, a full eigenvalue decomposition is used instead, which can be much more expensive. This argument is ignored if optimize is set to True.

Return type:

DoubleFactorizedHamiltonian

Returns:

The double-factorized Hamiltonian.

property norb: int

The number of spatial orbitals.

to_molecular_hamiltonian()[source]

Convert the DoubleFactorizedHamiltonian to a MolecularHamiltonian.

to_number_representation()[source]

Return the Hamiltonian in the “number” representation.

Return type:

DoubleFactorizedHamiltonian

to_z_representation()[source]

Return the Hamiltonian in the “Z” representation.

Return type:

DoubleFactorizedHamiltonian

class ffsim.FermionAction(action: bool, spin: bool, orb: int)[source]

Bases: NamedTuple

A fermionic action.

action: bool

Alias for field number 0

orb: int

Alias for field number 2

spin: bool

Alias for field number 1

class ffsim.FermionOperator(coeffs)

Bases: object

A fermionic operator.

A FermionOperator represents a linear combination of products of fermionic creation and annihilation operators. Initialize a FermionOperator by passing a dictionary mapping the terms in the linear combination to their associated coefficients. FermionOperators Can be added, subtracted, and multiplied, and they support multiplication and division by scalars. When multiplying by a scalar, the scalar should go on the left side of the multiplication operator, e.g. scalar * op, not op * scalar.

See How to use the FermionOperator class for an explanation of how to use this class.

Example:

# Note: Since FermionOperator is an unordered mapping, the order of
# the terms in the print outputs below may vary between runs.

import ffsim

op1 = ffsim.FermionOperator(
    {
        (ffsim.cre_a(0), ffsim.des_a(3)): 0.5,
        (ffsim.cre_a(3), ffsim.des_a(0)): -0.25,
        (ffsim.cre_b(1), ffsim.des_b(5), ffsim.cre_a(4)): 1 + 1j,
    }
)
print(2 * op1)
# prints
# FermionOperator({
#     (cre_b(1), des_b(5), cre_a(4)): 2+2j,
#     (cre_a(3), des_a(0)): -0.5,
#     (cre_a(0), des_a(3)): 1
# })

op2 = ffsim.FermionOperator(
    {
        (ffsim.cre_b(2),): 1j,
        (ffsim.des_a(3), ffsim.des_b(3)): -0.25,
    }
)
print(op1 + op2)
# prints
# FermionOperator({
#     (cre_a(3), des_a(0)): -0.25,
#     (cre_b(2)): 0+1j,
#     (des_a(3), des_b(3)): -0.25,
#     (cre_b(1), des_b(5), cre_a(4)): 1+1j,
#     (cre_a(0), des_a(3)): 0.5
# })

print(op1 * op2)
# prints
# FermionOperator({
#     (cre_b(1), des_b(5), cre_a(4), cre_b(2)): -1+1j,
#     (cre_a(0), des_a(3), des_a(3), des_b(3)): -0.125,
#     (cre_a(3), des_a(0), des_a(3), des_b(3)): 0.0625,
#     (cre_b(1), des_b(5), cre_a(4), des_a(3), des_b(3)): -0.25-0.25j,
#     (cre_a(0), des_a(3), cre_b(2)): 0+0.5j,
#     (cre_a(3), des_a(0), cre_b(2)): 0-0.25j
# })
Parameters:

coeffs (dict[tuple[tuple[bool, bool, int], ...], complex]) – The coefficients of the operator.

conserves_particle_number()

Return whether the operator conserves particle number.

Returns:

True if the operator conserves particle number, False otherwise.

Return type:

bool

conserves_spin_z()

Return whether the operator conserves the Z component of spin.

Returns:

True if the operator conserves the Z component of spin, False otherwise.

Return type:

bool

many_body_order()

Return the many-body order of the operator.

The many-body order is defined as the length of the longest term contained in the operator.

Returns:

The many-body order of the operator.

Return type:

int

normal_ordered()

Return the normal ordered form of the operator.

The normal ordered form of an operator is an equivalent operator in which each term has been reordered into a canonical ordering. In each term of a normal-ordered fermion operator, the operators comprising the term appear from left to right in descending lexicographic order by (action, spin, orb). That is, all creation operators appear before all annihilation operators; within creation/annihilation operators, spin beta operators appear before spin alpha operators, and larger orbital indices appear before smaller orbital indices.

Returns:

The normal-ordered fermion operator.

Return type:

FermionOperator

class ffsim.GivensAnsatzOp(norb, interaction_pairs, thetas, phis, phase_angles)[source]

Bases: object

A Givens rotation ansatz operator.

The Givens rotation ansatz consists of a sequence of Givens rotations followed by a layer of single-orbital phase gates.

Note that this ansatz does not implement any interactions between spin alpha and spin beta orbitals.

norb

The number of spatial orbitals.

Type:

int

interaction_pairs

The orbital pairs to apply the Givens rotations to.

Type:

list[tuple[int, int]]

thetas

The angles for the Givens rotations.

Type:

np.ndarray

phis

The optional phase angles for the Givens rotations.

Type:

np.ndarray | None

phase_angles

The optional phase angles for the layer of single-orbital phase gates.

Type:

np.ndarray | None

static from_orbital_rotation(orbital_rotation)[source]

Initialize the operator from an orbital rotation.

Parameters:

orbital_rotation (ndarray) – The orbital rotation.

Return type:

GivensAnsatzOp

static from_parameters(params, norb, interaction_pairs, with_phis=True, with_phase_angles=True)[source]

Initialize the operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • interaction_pairs (list[tuple[int, int]]) – The orbital pairs to apply the Givens rotation gates to.

  • with_phis (bool) – Whether to include complex phases for the Givens rotations.

  • with_phase_angles (bool) – Whether to include a layer of single-orbital phase gates.

Return type:

GivensAnsatzOp

static n_params(norb, interaction_pairs, with_phis=True, with_phase_angles=True)[source]

Return the number of parameters of an ansatz with given settings.

Parameters:
  • norb (int) – The number of spatial orbitals.

  • interaction_pairs (list[tuple[int, int]]) – The orbital pairs to apply the Givens rotation gates to.

  • with_phis (bool) – Whether to include complex phases for the Givens rotations.

  • with_phase_angles (bool) – Whether to include a layer of single-orbital phase gates.

Return type:

int

to_orbital_rotation()[source]

Convert the Givens ansatz operator to an orbital rotation.

Return type:

ndarray

to_parameters()[source]

Convert the operator to a real-valued parameter vector.

Return type:

ndarray

class ffsim.GivensAnsatzOperator(norb, interaction_pairs, thetas)[source]

Bases: object

A Givens rotation ansatz operator.

Warning

This class is deprecated. Use ffsim.GivensAnsatzOp instead.

The Givens rotation ansatz consists of a sequence of Givens rotations.

Note that this ansatz does not implement any interactions between spin alpha and spin beta orbitals.

norb

The number of spatial orbitals.

Type:

int

interaction_pairs

The orbital pairs to apply the Givens rotations to.

Type:

list[tuple[int, int]]

thetas

The angles for the Givens rotations.

Type:

np.ndarray

static from_parameters(params, norb, interaction_pairs)[source]

Initialize the operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • interaction_pairs (list[tuple[int, int]]) – The orbital pairs to apply the Givens rotation gates to.

Return type:

GivensAnsatzOperator

to_parameters()[source]

Convert the operator to a real-valued parameter vector.

Return type:

ndarray

class ffsim.HopGateAnsatzOperator(norb, interaction_pairs, thetas, final_orbital_rotation=None)[source]

Bases: object

A hop gate ansatz operator.

The hop gate ansatz consists of a sequence of hop gates.

Note that this ansatz does not implement any interactions between spin alpha and spin beta orbitals. It was designed to be used with entanglement forging.

norb

The number of spatial orbitals.

Type:

int

interaction_pairs

The orbital pairs to apply the hop gates to.

Type:

list[tuple[int, int]]

thetas

The rotation angles for the hop gates.

Type:

np.ndarray

final_orbital_rotation

An optional final orbital rotation to append to the ansatz, used to optimize the orbital basis.

Type:

np.ndarray

static from_parameters(params, norb, interaction_pairs, with_final_orbital_rotation=False)[source]

Initialize the operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • interaction_pairs (list[tuple[int, int]]) – The orbital pairs to apply the hop gates to.

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the ansatz operator.

Return type:

HopGateAnsatzOperator

to_parameters()[source]

Convert the operator to a real-valued parameter vector.

Return type:

ndarray

class ffsim.MolecularData(core_energy, one_body_integrals, two_body_integrals, norb, nelec, atom=None, basis=None, spin=None, symmetry=None, mo_coeff=None, mo_occ=None, active_space=None, hf_energy=None, hf_mo_coeff=None, hf_mo_occ=None, mp2_energy=None, mp2_t2=None, ccsd_energy=None, ccsd_t1=None, ccsd_t2=None, cisd_energy=None, cisd_vec=None, sci_energy=None, sci_vec=None, fci_energy=None, fci_vec=None, dipole_integrals=None, orbital_symmetries=None)[source]

Bases: object

Class for storing molecular data.

core_energy

The core energy.

Type:

float

one_body_integrals

The one-body integrals.

Type:

np.ndarray

two_body_integrals

The two-body integrals in compressed format.

Type:

np.ndarray

norb

The number of spatial orbitals.

Type:

int

nelec

The number of alpha and beta electrons.

Type:

tuple[int, int]

atom

The coordinates of the atoms in the molecule.

Type:

list[tuple[str, tuple[float, float, float]]] | None

basis

The basis set, e.g. “sto-6g”.

Type:

str | None

spin

The spin of the molecule.

Type:

int | None

symmetry

The symmetry of the molecule.

Type:

str | None

mo_coeff

Molecular orbital coefficients in the AO basis.

Type:

np.ndarray | None

mo_occ

Molecular orbital occupancies.

Type:

np.ndarray | None

active_space

The molecular orbitals included in the active space.

Type:

list[int] | None

hf_energy

The Hartree-Fock energy.

Type:

float | None

hf_mo_coeff

Hartree-Fock canonical orbital coefficients in the AO basis.

Type:

np.ndarray | None

hf_mo_occ

Hartree-Fock canonical orbital occupancies.

Type:

np.ndarray | None

mp2_energy

The MP2 energy.

Type:

float | None

mp2_t2

The MP2 t2 amplitudes.

Type:

np.ndarray | tuple[np.ndarray, np.ndarray, np.ndarray] | None

ccsd_energy

The CCSD energy.

Type:

float | None

ccsd_t1

The CCSD t1 amplitudes.

Type:

np.ndarray | tuple[np.ndarray, np.ndarray] | None

ccsd_t2

The CCSD t2 amplitudes.

Type:

np.ndarray | tuple[np.ndarray, np.ndarray, np.ndarray] | None

cisd_energy

The CISD energy.

Type:

float | None

cisd_vec

The CISD state vector.

Type:

np.ndarray | None

sci_energy

The SCI energy.

Type:

float | None

sci_vec

The SCI state vector coefficients, spin alpha strings, and spin beta strings.

Type:

tuple[np.ndarray, np.ndarray, np.ndarray] | None

fci_energy

The FCI energy.

Type:

float | None

fci_vec

The FCI state vector.

Type:

np.ndarray | None

dipole_integrals

The dipole integrals.

Type:

np.ndarray | None

orbital_symmetries

The orbital symmetries.

Type:

list[str] | None

static from_fcidump(file)[source]

Initialize a MolecularData from an FCIDUMP file.

Parameters:

file (str | bytes | PathLike) – The FCIDUMP file path.

Return type:

MolecularData

static from_json(file, compression=None)[source]

Load a MolecularData from a (possibly compressed) JSON file.

Parameters:
  • file (str | bytes | PathLike) – The file path to read from.

  • compression (str | None) – The compression algorithm, if any, which was used to compress the file. Options: "gzip", "bz2", "lzma".

Return type:

MolecularData

Returns: The MolecularData object.

static from_mole(molecule, active_space=None, scf_func=<function RHF>)[source]

Initialize a MolecularData object from a PySCF molecule.

Warning

This method is deprecated. Instead, pass an SCF object directly to from_scf().

Parameters:
  • molecule (Mole) – The molecule.

  • active_space (Iterable[int] | None) – An optional list of orbitals to use for the active space.

  • scf_func – The PySCF SCF function to use for the Hartree-Fock calculation.

Return type:

MolecularData

static from_scf(hartree_fock, active_space=None)[source]

Initialize a MolecularData object from a Hartree-Fock calculation.

Parameters:
  • hartree_fock (SCF) – The Hartree-Fock object.

  • active_space (Iterable[int] | None) – An optional list of orbitals to use for the active space.

Return type:

MolecularData

property hamiltonian: MolecularHamiltonian

The Hamiltonian defined by the molecular data.

property mole: Mole

The PySCF Mole class for this molecular data.

run_ccsd(t1=None, t2=None, *, store_t1=False, store_t2=False)[source]

Run CCSD and store results.

Return type:

None

run_cisd(*, store_cisd_vec=False)[source]

Run CISD and store results.

Return type:

None

run_fci(*, store_fci_vec=False)[source]

Run FCI and store results.

Return type:

None

run_mp2(*, store_t2=False)[source]

Run MP2 and store results.

run_sci(*, store_sci_vec=False)[source]

Run SCI and store results.

Return type:

None

property scf: SCF

A PySCF SCF class for this molecular data.

to_fcidump(file)[source]

Save data to disk in FCIDUMP format.

Note

The FCIDUMP format does not retain all information stored in the MolecularData object. To serialize a MolecularData object losslessly, use the to_json() method to save to JSON format.

Parameters:

file (str | bytes | PathLike) – The file path to save to.

Return type:

None

to_json(file, compression=None)[source]

Serialize to JSON format, optionally compressed, and save to disk.

Parameters:
  • file (str | bytes | PathLike) – The file path to save to.

  • compression (str | None) – The optional compression algorithm to use. Options: "gzip", "bz2", "lzma".

Return type:

None

class ffsim.MolecularHamiltonian(one_body_tensor, two_body_tensor, constant=0.0)[source]

Bases: object

A molecular Hamiltonian.

A Hamiltonian of the form

\[H = \sum_{\sigma, pq} h_{pq} a^\dagger_{\sigma, p} a_{\sigma, q} + \frac12 \sum_{\sigma \tau, pqrs} h_{pqrs} a^\dagger_{\sigma, p} a^\dagger_{\tau, r} a_{\tau, s} a_{\sigma, q} + \text{constant}.\]

Here \(h_{pq}\) is called the one-body tensor and \(h_{pqrs}\) is called the two-body tensor.

one_body_tensor

The one-body tensor.

Type:

np.ndarray

two_body_tensor

The two-body tensor.

Type:

np.ndarray

constant

The constant.

Type:

float

static from_fcidump(file)[source]

Initialize a MolecularHamiltonian from an FCIDUMP file.

Warning

This function is deprecated. Instead, use MolecularData.from_fcidump and then access the hamiltonian attribute of the returned MolecularData.

Parameters:

file (str | bytes | PathLike) – The FCIDUMP file path.

Return type:

MolecularHamiltonian

property norb: int

The number of spatial orbitals.

rotated(orbital_rotation)[source]

Return the Hamiltonian in a rotated orbital basis.

Given an orbital rotation \(\mathcal{U}\), returns the operator

\[\mathcal{U} H \mathcal{U}^\dagger\]

where \(H\) is the original Hamiltonian.

Parameters:

orbital_rotation (ndarray) – The orbital rotation.

Return type:

MolecularHamiltonian

Returns:

The rotated Hamiltonian.

class ffsim.NumNumAnsatzOpSpinBalanced(norb, interaction_pairs, thetas)[source]

Bases: object

A number-number interaction ansatz operator.

The number-number interaction ansatz consists of a sequence of number-number interactions.

norb

The number of spatial orbitals.

Type:

int

interaction_pairs

The orbital pairs to apply the number-number interactions to.

Type:

list[tuple[int, int]]

thetas

The angles for the number-number interactions.

Type:

np.ndarray

static from_diag_coulomb_mats(diag_coulomb_mats)[source]

Initialize the operator from a diagonal Coulomb matrix.

Parameters:

diag_coulomb_mats (tuple[ndarray, ndarray] | ndarray) – The diagonal Coulomb matrices. Should be a pair of matrices, with the first matrix representing same-spin interactions and the second matrix representing different-spin interactions.

Return type:

NumNumAnsatzOpSpinBalanced

static from_parameters(params, norb, interaction_pairs)[source]

Initialize the operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • interaction_pairs (tuple[list[tuple[int, int]], list[tuple[int, int]]]) – The orbital pairs to apply the number-number interactions to.

Return type:

NumNumAnsatzOpSpinBalanced

static n_params(interaction_pairs)[source]

Return the number of parameters of an ansatz with given settings.

Parameters:

interaction_pairs (list[tuple[int, int]]) – The orbital pairs to apply the number-number interactions to.

Return type:

int

to_diag_coulomb_mats()[source]

Convert the operator to diagonal Coulomb matrices.

Return type:

ndarray

Returns:

A Numpy array of shape (2, norb, norb) holding two matrices. The first matrix holds the same-spin interactions and the second matrix holds the different-spin interactions.

to_parameters()[source]

Convert the operator to a real-valued parameter vector.

Return type:

ndarray

class ffsim.ProductStateSum(coeffs: np.ndarray, states: list[tuple[np.ndarray, np.ndarray]])[source]

Bases: NamedTuple

A linear combination of product states.

Given a ProductStateSum prod_state_sum, the full state vector can be reconstructed as

sum(
    coeff * np.kron(vec_a, vec_b)
    for coeff, (vec_a, vec_b) in zip(
        prod_state_sum.coeffs, prod_state_sum.states
    )
)
coeffs: ndarray

Alias for field number 0

states: list[tuple[ndarray, ndarray]]

Alias for field number 1

class ffsim.RealUCJOperator(diag_coulomb_mats_alpha_alpha, diag_coulomb_mats_alpha_beta, orbital_rotations, final_orbital_rotation=None)[source]

Bases: object

Real-valued unitary cluster Jastrow operator.

Warning

The RealUCJOperator class is deprecated. Use ffsim.UCJOpSpinBalanced instead.

A real-valued unitary cluster Jastrow (UCJ) operator has the form

\[\prod_{k = 1}^L \mathcal{W_k^*} e^{i \mathcal{-J}_k} \mathcal{W_k}^T \mathcal{W_k} e^{i \mathcal{J}_k} \mathcal{W_k^\dagger}\]

where each \(\mathcal{W_k}\) is an orbital rotation and each \(\mathcal{J}\) is a diagonal Coulomb operator of the form

\[\mathcal{J} = \frac12\sum_{ij,\sigma \tau} \mathbf{J}^{\sigma \tau}_{ij} n_{i,\sigma} n_{j,\tau}.\]

In order that the operator commutes with the total spin Z operator, we enforce that \(\mathbf{J}^{\alpha\alpha} = \mathbf{J}^{\beta\beta}\) and \(\mathbf{J}^{\alpha\beta} = \mathbf{J}^{\beta\alpha}\). As a result, we have two sets of matrices for describing the diagonal Coulomb operators: “alpha-alpha” matrices containing coefficients for terms involving the same spin, and “alpha-beta” matrices containing coefficients for terms involving different spins.

To support variational optimization of the orbital basis, an optional final orbital rotation can be included in the operator, to be performed at the end.

diag_coulomb_mats_alpha_alpha

The “alpha-alpha” diagonal Coulomb matrices.

diag_coulomb_mats_alpha_beta

The “alpha-beta” diagonal Coulomb matrices.

orbital_rotations

The orbital rotations.

final_orbital_rotation

The optional final orbital rotation.

static from_parameters(params, *, norb, n_reps, alpha_alpha_indices=None, alpha_beta_indices=None, with_final_orbital_rotation=False)[source]

Initialize the real UCJ operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • n_reps (int) – The number of ansatz repetitions (\(L\) from the docstring of this class).

  • alpha_alpha_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the “alpha-alpha” diagonal Coulomb matrices (see the docstring of this class). If not specified, all matrix entries are allowed to be nonzero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error.

  • alpha_beta_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the “alpha-beta” diagonal Coulomb matrices (see the docstring of this class). If not specified, all matrix entries are allowed to be nonzero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error.

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the operator.

Return type:

RealUCJOperator

Returns:

The real UCJ operator constructed from the given parameters.

Raises:
  • ValueError – alpha_alpha_indices contains lower triangular indices.

  • ValueError – alpha_beta_indices contains lower triangular indices.

static from_t_amplitudes(t2, *, t1=None, n_reps=None, tol=1e-08)[source]

Initialize the real UCJ operator from t2 (and optionally t1) amplitudes.

Return type:

RealUCJOperator

static n_params(norb, n_reps, *, alpha_alpha_indices=None, alpha_beta_indices=None, with_final_orbital_rotation=False)[source]

Return the number of parameters of an ansatz with given settings.

Return type:

int

property n_reps

The number of ansatz repetitions.

property norb

The number of spatial orbitals.

to_parameters(*, alpha_alpha_indices=None, alpha_beta_indices=None)[source]

Convert the real UCJ operator to a real-valued parameter vector.

If alpha_alpha_indices or alpha_beta_indices is specified, the returned parameter vector will incorporate only the diagonal Coulomb matrix entries corresponding to the given indices, so the original operator will not be recoverable from the parameter vector.

Parameters:
  • alpha_alpha_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the “alpha-alpha” diagonal Coulomb matrices (see the docstring of this class). If not specified, all matrix entries are allowed to be nonzero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error.

  • alpha_beta_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the “alpha-beta” diagonal Coulomb matrices (see the docstring of this class). If not specified, all matrix entries are allowed to be nonzero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error.

Return type:

ndarray

Returns:

The real-valued parameter vector.

Raises:
  • ValueError – alpha_alpha_indices contains lower triangular indices.

  • ValueError – alpha_beta_indices contains lower triangular indices.

to_t_amplitudes(nocc=None)[source]

Convert the UCJ operator to t2 (and possibly t1) amplitudes.

Return type:

ndarray | tuple[ndarray, ndarray]

class ffsim.SingleFactorizedHamiltonian(one_body_tensor, one_body_squares, constant=0.0)[source]

Bases: object

A Hamiltonian in the single-factorized representation.

The single-factorized form of the molecular Hamiltonian is

\[H = \sum_{\sigma, pq} \kappa_{pq} a^\dagger_{\sigma, p} a_{\sigma, q} + \frac12 \sum_{t=1}^L \left(\mathcal{M}^{(t)}\right)^2 + \text{constant}'.\]

Here each \(\mathcal{M}^{(t)}\) is a one-body operator:

\[\mathcal{M}^{(t)} = \sum_{\sigma, pq} M^{(t)}_{pq} a^\dagger_{\sigma, p} a_{\sigma, q}\]

where each \(M^{(t)}\) is a Hermitian matrix.

one_body_tensor

The one-body tensor \(\kappa\).

Type:

np.ndarray

one_body_squares

The one-body tensors \(M^{(t)}\) whose squares are summed in the Hamiltonian.

Type:

np.ndarray

constant

The constant.

Type:

float

expectation_product_state(vec, norb, nelec)[source]

Return expectation value with respect to a product state.

Parameters:
  • vec (tuple[ndarray, ndarray]) – The product state, as a pair (vec_a, vec_b) containing the alpha and beta components of the state.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

Return type:

float

static from_molecular_hamiltonian(hamiltonian, *, tol=1e-08, max_vecs=None, cholesky=True)[source]

Initialize a SingleFactorizedHamiltonian from a MolecularHamiltonian.

The number of terms in the decomposition depends on the allowed error threshold. A larger error threshold leads to a smaller number of terms. Furthermore, the max_vecs parameter specifies an optional upper bound on the number of terms.

Note: Currently, only real-valued two-body tensors are supported.

Parameters:
  • hamiltonian (MolecularHamiltonian) – The Hamiltonian whose single-factorized representation to compute.

  • 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_vecs (int | None) – An optional limit on the number of terms to keep in the decomposition of the two-body tensor. This argument overrides tol.

  • cholesky (bool) – Whether to perform the factorization using a modified Cholesky decomposition. If False, a full eigenvalue decomposition is used instead, which can be much more expensive.

Return type:

SingleFactorizedHamiltonian

Returns:

The single-factorized Hamiltonian.

property norb: int

The number of spatial orbitals.

reduced_matrix_product_states(vecs, norb, nelec)[source]

Return reduced matrix within a subspace spanned by some product states.

Given a list of product states \(\{\lvert \alpha_i, \beta_i \rangle\}\), returns the matrix M where \(M_{ij} = \langle \alpha_i, \beta_i \rvert H \lvert \alpha_j, \beta_j \rangle\).

Parameters:
  • vecs (Sequence[tuple[ndarray, ndarray]]) – The product states, as a list of pairs (vec_a, vec_b) containing the alpha and beta components of each state.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

Return type:

ndarray

Returns:

The reduced matrix.

class ffsim.Spin(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: Flag

Enumeration for indicating alpha, beta, or both spins.

ALPHA = 1

Use this to indicate spin alpha.

ALPHA_AND_BETA = 3

Use this to indicate both spin alpha and spin beta.

BETA = 2

Use this to indicate spin beta.

class ffsim.StateVector(vec, norb, nelec)[source]

Bases: object

A state vector in the FCI representation.

vec

Array of state vector coefficients.

norb

The number of spatial orbitals.

nelec

Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

class ffsim.SupportsApplyUnitary(*args, **kwargs)[source]

Bases: Protocol

An object that can apply a unitary transformation to a vector.

class ffsim.SupportsApproximateEquality(*args, **kwargs)[source]

Bases: Protocol

An object that can be compared approximately.

class ffsim.SupportsDiagonal(*args, **kwargs)[source]

Bases: Protocol

A linear operator whose diagonal entries can be returned.

class ffsim.SupportsFermionOperator(*args, **kwargs)[source]

Bases: Protocol

An object that can be converted to a FermionOperator.

class ffsim.SupportsLinearOperator(*args, **kwargs)[source]

Bases: Protocol

An object that can be converted to a SciPy LinearOperator.

class ffsim.SupportsTrace(*args, **kwargs)[source]

Bases: Protocol

A linear operator whose trace can be computed.

class ffsim.UCJOpSpinBalanced(diag_coulomb_mats, orbital_rotations, final_orbital_rotation=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Bases: object

A spin-balanced unitary cluster Jastrow operator.

A unitary cluster Jastrow (UCJ) operator has the form

\[\prod_{k = 1}^L \mathcal{U}_k e^{i \mathcal{J}_k} \mathcal{U}_k^\dagger\]

where each \(\mathcal{U_k}\) is an orbital rotation and each \(\mathcal{J}\) is a diagonal Coulomb operator of the form

\[\mathcal{J} = \frac12\sum_{\sigma \tau, ij} \mathbf{J}^{(\sigma \tau)}_{ij} n_{\sigma, i} n_{\tau, j}.\]

For the spin-balanced operator, we require that \(\mathbf{J}^{(\alpha \alpha)} = \mathbf{J}^{(\beta \beta)}\) and \(\mathbf{J}^{(\alpha \beta)} = \mathbf{J}^{(\beta \alpha)}\). Therefore, each diagonal Coulomb operator is described by 2 matrices, \(\mathbf{J}^{(\alpha \alpha)}\) and \(\mathbf{J}^{(\alpha \beta)}\), and both of these matrices are symmetric. Furthermore, each orbital rotation is described by a single matrix because the same orbital rotation is applied to both spin alpha and spin beta. The number of terms \(L\) is referred to as the number of ansatz repetitions and is accessible via the n_reps attribute.

To support variational optimization of the orbital basis, an optional final orbital rotation can be included in the operator, to be performed at the end.

diag_coulomb_mats

The diagonal Coulomb matrices, as a Numpy array of shape (n_reps, 2, norb, norb) The last two axes index the rows and columns of the matrices, and the third from last axis, which has 2 dimensions, indexes the spin interaction type of the matrix: alpha-alpha, and then alpha-beta. The first axis indexes the ansatz repetitions.

Type:

np.ndarray

orbital_rotations

The orbital rotations, as a Numpy array of shape (n_reps, norb, norb).

Type:

np.ndarray

final_orbital_rotation

The optional final orbital rotation, as a Numpy array of shape (norb, norb).

Type:

np.ndarray | None

static from_parameters(params, *, norb, n_reps, interaction_pairs=None, with_final_orbital_rotation=False)[source]

Initialize the UCJ operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • n_reps (int) – The number of ansatz repetitions.

  • interaction_pairs (tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a pair of lists, for alpha-alpha and alpha-beta interactions, in that order. Either list can be substituted with None to indicate no restrictions on interactions. Each list should contain pairs of integers representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. Each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the operator.

Return type:

UCJOpSpinBalanced

Returns:

The UCJ operator constructed from the given parameters.

Raises:
  • ValueError – The number of parameters passed did not match the number expected based on the function inputs.

  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list contained lower triangular pairs.

static from_t_amplitudes(t2, *, t1=None, n_reps=None, interaction_pairs=None, tol=1e-08)[source]

Initialize the UCJ operator from t2 (and optionally t1) amplitudes.

Performs a double-factorization of the t2 amplitudes and constructs the ansatz repetitions from the terms of the decomposition, up to an optionally specified number of ansatz repetitions. Terms are included in decreasing order of the absolute value of the corresponding eigenvalue in the factorization.

Parameters:
  • t2 (ndarray) – The t2 amplitudes.

  • t1 (ndarray | None) – The t1 amplitudes.

  • n_reps (int | None) – The number of ansatz repetitions. If not specified, then it is set to the number of terms resulting from the double-factorization of the t2 amplitudes. If the specified number of repetitions is larger than the number of terms resulting from the double-factorization, then the ansatz is padded with additional identity operators up to the specified number of repetitions.

  • interaction_pairs (tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a pair of lists, for alpha-alpha and alpha-beta interactions, in that order. Either list can be substituted with None to indicate no restrictions on interactions. Each list should contain pairs of integers representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. Each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

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

Return type:

UCJOpSpinBalanced

Returns:

The UCJ operator with parameters initialized from the t2 amplitudes.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list contained lower triangular pairs.

static n_params(norb, n_reps, *, interaction_pairs=None, with_final_orbital_rotation=False)[source]

Return the number of parameters of an ansatz with given settings.

Parameters:
  • n_reps (int) – The number of ansatz repetitions.

  • interaction_pairs (tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a pair of lists, for alpha-alpha and alpha-beta interactions, in that order. Either list can be substituted with None to indicate no restrictions on interactions. Each list should contain pairs of integers representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. Each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the operator.

Return type:

int

Returns:

The number of parameters of the ansatz.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list contained lower triangular pairs.

property n_reps

The number of ansatz repetitions.

property norb

The number of spatial orbitals.

to_parameters(*, interaction_pairs=None)[source]

Convert the UCJ operator to a real-valued parameter vector.

Note

If interaction_pairs is specified, the returned parameter vector will incorporate only the diagonal Coulomb matrix entries corresponding to the specified interactions, so the original operator will not be recoverable from the parameter vector.

Parameters:

interaction_pairs (tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a pair of lists, for alpha-alpha and alpha-beta interactions, in that order. Either list can be substituted with None to indicate no restrictions on interactions. Each list should contain pairs of integers representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. Each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

Return type:

ndarray

Returns:

The real-valued parameter vector.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list contained lower triangular pairs.

class ffsim.UCJOpSpinUnbalanced(diag_coulomb_mats, orbital_rotations, final_orbital_rotation=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Bases: object

A spin-unbalanced unitary cluster Jastrow operator.

A unitary cluster Jastrow (UCJ) operator has the form

\[\prod_{k = 1}^L \mathcal{U}_k e^{i \mathcal{J}_k} \mathcal{U}_k^\dagger\]

where each \(\mathcal{U_k}\) is an orbital rotation and each \(\mathcal{J}\) is a diagonal Coulomb operator of the form

\[\mathcal{J} = \frac12\sum_{\sigma \tau, ij} \mathbf{J}^{(\sigma \tau)}_{ij} n_{\sigma, i} n_{\tau, j}.\]

Since \(\mathbf{J}^{(\sigma \tau)}_{ij} = \mathbf{J}^{(\tau \sigma)}_{ji}\), each diagonal Coulomb operator requires 3 matrices for its description: \(\mathbf{J}^{(\alpha \alpha)}\), \(\mathbf{J}^{(\alpha \beta)}\), and \(\mathbf{J}^{(\beta \beta)}\). The number of terms \(L\) is referred to as the number of ansatz repetitions and is accessible via the n_reps attribute.

To support variational optimization of the orbital basis, an optional final orbital rotation can be included in the operator, to be performed at the end.

diag_coulomb_mats

The diagonal Coulomb matrices, as a Numpy array of shape (n_reps, 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 ansatz repetitions.

Type:

np.ndarray

orbital_rotations

The orbital rotations, as a Numpy array of shape (n_reps, 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 ansatz repetitions.

Type:

np.ndarray

final_orbital_rotation

The optional final orbital rotation, as a Numpy array of shape (2, norb, norb). This can be viewed as a list of two orbital rotations, the first one for spin alpha and the second one for spin beta.

Type:

np.ndarray | None

static from_parameters(params, *, norb, n_reps, interaction_pairs=None, with_final_orbital_rotation=False)[source]

Initialize the UCJ operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • n_reps (int) – The number of ansatz repetitions.

  • interaction_pairs (tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None, list[tuple[int, int]] | None] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a tuple of 3 lists, for alpha-alpha, alpha-beta, and beta-beta interactions, in that order. Any list can be substituted with None to indicate no restrictions on interactions. Each list should contain pairs of integers representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. For the alpha-alpha and beta-beta interactions, each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the operator.

Return type:

UCJOpSpinUnbalanced

Returns:

The UCJ operator constructed from the given parameters.

Raises:
  • ValueError – The number of parameters passed did not match the number expected based on the function inputs.

  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list for alpha-alpha or beta-beta interactions contained lower triangular pairs.

static from_t_amplitudes(t2, *, t1=None, n_reps=None, interaction_pairs=None, tol=1e-08)[source]

Initialize the UCJ operator from t2 (and optionally t1) amplitudes.

Performs a double-factorization of the t2 amplitudes and constructs the ansatz repetitions from the terms of the decomposition, up to an optionally specified number of repetitions. Terms are included in decreasing order of the magnitude of the corresponding singular value in the factorization.

Parameters:
  • t2 (tuple[ndarray, ndarray, ndarray]) – The t2 amplitudes. This should be a tuple of 3 Numpy arrays, (t2aa, t2ab, t2bb), containing the alpha-alpha, alpha-beta, and beta-beta t2 amplitudes.

  • t1 (tuple[ndarray, ndarray] | None) – The t1 amplitudes. This should be a pair of Numpy arrays, (t1a, t1b), containing the alpha and beta t1 amplitudes.

  • n_reps (int | tuple[int, int] | None) – The number of ansatz repetitions. You can pass a single integer or a pair of integers. If a single integer, terms from the alpha-beta t2 amplitudes are used before including any terms from the alpha-alpha and beta-beta t2 amplitudes. If a pair of integers, then the first integer specifies the number of terms to use from the alpha-beta t2 amplitudes, and the second integer specifies the number of terms to use from the alpha-alpha and beta-beta t2 amplitudes. If not specified, then it is set to the number of terms resulting from the double-factorization of the t2 amplitudes. If the specified number of repetitions is larger than the number of terms resulting from the double-factorization, then the ansatz is padded with additional identity operators up to the specified number of repetitions.

  • interaction_pairs (tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None, list[tuple[int, int]] | None] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a tuple of 3 lists, for alpha-alpha, alpha-beta, and beta-beta interactions, in that order. Any list can be substituted with None to indicate no restrictions on interactions. Each list should contain pairs of integers representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. For the alpha-alpha and beta-beta interactions, each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

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

Return type:

UCJOpSpinUnbalanced

Returns:

The UCJ operator with parameters initialized from the t2 amplitudes.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list for alpha-alpha or beta-beta interactions contained lower triangular pairs.

static n_params(norb, n_reps, *, interaction_pairs=None, with_final_orbital_rotation=False)[source]

Return the number of parameters of an ansatz with given settings.

Parameters:
  • n_reps (int) – The number of ansatz repetitions.

  • interaction_pairs (tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None, list[tuple[int, int]] | None] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a tuple of 3 lists, for alpha-alpha, alpha-beta, and beta-beta interactions, in that order. Any list can be substituted with None to indicate no restrictions on interactions. Each list should contain pairs of integers representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. For the alpha-alpha and beta-beta interactions, each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the operator.

Return type:

int

Returns:

The number of parameters of the ansatz.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list for alpha-alpha or beta-beta interactions contained lower triangular pairs.

property n_reps

The number of ansatz repetitions.

property norb

The number of spatial orbitals.

to_parameters(interaction_pairs=None)[source]

Convert the UCJ operator to a real-valued parameter vector.

Note

If interaction_pairs is specified, the returned parameter vector will incorporate only the diagonal Coulomb matrix entries corresponding to the specified interactions, so the original operator will not be recoverable from the parameter vector.

Parameters:

interaction_pairs (tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None, list[tuple[int, int]] | None] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a tuple of 3 lists, for alpha-alpha, alpha-beta, and beta-beta interactions, in that order. Any list can be substituted with None to indicate no restrictions on interactions. Each list should contain pairs of integers representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. For the alpha-alpha and beta-beta interactions, each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

Return type:

ndarray

Returns:

The real-valued parameter vector.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list for alpha-alpha or beta-beta interactions contained lower triangular pairs.

class ffsim.UCJOpSpinless(diag_coulomb_mats, orbital_rotations, final_orbital_rotation=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Bases: object

A spinless unitary cluster Jastrow operator.

A spinless unitary cluster Jastrow (UCJ) operator has the form

\[\prod_{k = 1}^L \mathcal{U}_k e^{i \mathcal{J}_k} \mathcal{U}_k^\dagger\]

where each \(\mathcal{U_k}\) is an orbital rotation and each \(\mathcal{J}\) is a diagonal Coulomb operator of the form

\[\mathcal{J} = \frac12\sum_{ij} \mathbf{J}_{ij} n_{i} n_{j}.\]

where mathbf{J} is a real symmetric matrix. The number of terms \(L\) is referred to as the number of ansatz repetitions and is accessible via the n_reps attribute.

To support variational optimization of the orbital basis, an optional final orbital rotation can be included in the operator, to be performed at the end.

diag_coulomb_mats

The diagonal Coulomb matrices, as a Numpy array of shape (n_reps, norb, norb)

Type:

np.ndarray

orbital_rotations

The orbital rotations, as a Numpy array of shape (n_reps, norb, norb).

Type:

np.ndarray

final_orbital_rotation

The optional final orbital rotation, as a Numpy array of shape (norb, norb).

Type:

np.ndarray | None

static from_parameters(params, *, norb, n_reps, interaction_pairs=None, with_final_orbital_rotation=False)[source]

Initialize the UCJ operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • n_reps (int) – The number of ansatz repetitions.

  • interaction_pairs (list[tuple[int, int]] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a list of integer pairs representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. Each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the operator.

Return type:

UCJOpSpinless

Returns:

The UCJ operator constructed from the given parameters.

Raises:
  • ValueError – The number of parameters passed did not match the number expected based on the function inputs.

  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list contained lower triangular pairs.

static from_t_amplitudes(t2, *, t1=None, n_reps=None, interaction_pairs=None, tol=1e-08)[source]

Initialize the UCJ operator from t2 (and optionally t1) amplitudes.

Performs a double-factorization of the t2 amplitudes and constructs the ansatz repetitions from the terms of the decomposition, up to an optionally specified number of ansatz repetitions. Terms are included in decreasing order of the absolute value of the corresponding eigenvalue in the factorization.

Parameters:
  • t2 (ndarray) – The t2 amplitudes.

  • t1 (ndarray | None) – The t1 amplitudes.

  • n_reps (int | None) – The number of ansatz repetitions. If not specified, then it is set to the number of terms resulting from the double-factorization of the t2 amplitudes. If the specified number of repetitions is larger than the number of terms resulting from the double-factorization, then the ansatz is padded with additional identity operators up to the specified number of repetitions.

  • interaction_pairs (list[tuple[int, int]] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a list of integer pairs representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. Each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

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

Return type:

UCJOpSpinless

Returns:

The UCJ operator with parameters initialized from the t2 amplitudes.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list contained lower triangular pairs.

static n_params(norb, n_reps, *, interaction_pairs=None, with_final_orbital_rotation=False)[source]

Return the number of parameters of an ansatz with given settings.

Parameters:
  • n_reps (int) – The number of ansatz repetitions.

  • interaction_pairs (list[tuple[int, int]] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a list of integer pairs representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. Each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the operator.

Return type:

int

Returns:

The number of parameters of the ansatz.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list contained lower triangular pairs.

property n_reps

The number of ansatz repetitions.

property norb

The number of spatial orbitals.

to_parameters(*, interaction_pairs=None)[source]

Convert the UCJ operator to a real-valued parameter vector.

Note

If interaction_pairs is specified, the returned parameter vector will incorporate only the diagonal Coulomb matrix entries corresponding to the specified interactions, so the original operator will not be recoverable from the parameter vector.

Parameters:

interaction_pairs (list[tuple[int, int]] | None) – Optional restrictions on allowed orbital interactions for the diagonal Coulomb operators. If specified, interaction_pairs should be a list of integer pairs representing the orbitals that are allowed to interact. These pairs can also be interpreted as indices of diagonal Coulomb matrix entries that are allowed to be nonzero. Each integer pair must be upper triangular, that is, of the form \((i, j)\) where \(i \leq j\).

Return type:

ndarray

Returns:

The real-valued parameter vector.

Raises:
  • ValueError – Interaction pairs list contained duplicate interactions.

  • ValueError – Interaction pairs list contained lower triangular pairs.

class ffsim.UCJOperator(diag_coulomb_mats_alpha_alpha, diag_coulomb_mats_alpha_beta, orbital_rotations, final_orbital_rotation=None)[source]

Bases: object

A unitary cluster Jastrow operator.

Warning

The UCJOperator class is deprecated. Use ffsim.UCJOpSpinBalanced instead.

A unitary cluster Jastrow (UCJ) operator has the form

\[\prod_{k = 1}^L \mathcal{W}_k e^{i \mathcal{J}_k} \mathcal{W}_k^\dagger\]

where each \(\mathcal{W_k}\) is an orbital rotation and each \(\mathcal{J}\) is a diagonal Coulomb operator of the form

\[\mathcal{J} = \frac12\sum_{\sigma \tau, ij} \mathbf{J}^{\sigma \tau}_{ij} n_{\sigma, i} n_{\tau, j}.\]

In order that the operator commutes with the total spin Z operator, we enforce that \(\mathbf{J}^{\alpha\alpha} = \mathbf{J}^{\beta\beta}\) and \(\mathbf{J}^{\alpha\beta} = \mathbf{J}^{\beta\alpha}\). As a result, we have two sets of matrices for describing the diagonal Coulomb operators: “alpha-alpha” matrices containing coefficients for terms involving the same spin, and “alpha-beta” matrices containing coefficients for terms involving different spins.

To support variational optimization of the orbital basis, an optional final orbital rotation can be included in the operator, to be performed at the end.

diag_coulomb_mats_alpha_alpha

The “alpha-alpha” diagonal Coulomb matrices.

Type:

np.ndarray

diag_coulomb_mats_alpha_beta

The “alpha-beta” diagonal Coulomb matrices.

Type:

np.ndarray

orbital_rotations

The orbital rotations.

Type:

np.ndarray

final_orbital_rotation

The optional final orbital rotation.

Type:

np.ndarray

static from_parameters(params, *, norb, n_reps, alpha_alpha_indices=None, alpha_beta_indices=None, with_final_orbital_rotation=False)[source]

Initialize the UCJ operator from a real-valued parameter vector.

Parameters:
  • params (ndarray) – The real-valued parameter vector.

  • norb (int) – The number of spatial orbitals.

  • n_reps (int) – The number of ansatz repetitions (\(L\) from the docstring of this class).

  • alpha_alpha_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the “alpha-alpha” diagonal Coulomb matrices (see the docstring of this class). If not specified, all matrix entries are allowed to be nonzero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error.

  • alpha_beta_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the “alpha-beta” diagonal Coulomb matrices (see the docstring of this class). If not specified, all matrix entries are allowed to be nonzero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error.

  • with_final_orbital_rotation (bool) – Whether to include a final orbital rotation in the operator.

Return type:

UCJOperator

Returns:

The UCJ operator constructed from the given parameters.

Raises:
  • ValueError – alpha_alpha_indices contains lower triangular indices.

  • ValueError – alpha_beta_indices contains lower triangular indices.

static from_t_amplitudes(t2, *, t1=None, n_reps=None, tol=1e-08)[source]

Initialize the UCJ operator from t2 (and optionally t1) amplitudes.

Return type:

UCJOperator

static n_params(norb, n_reps, *, alpha_alpha_indices=None, alpha_beta_indices=None, with_final_orbital_rotation=False)[source]

Return the number of parameters of an ansatz with given settings.

Return type:

int

property n_reps

The number of ansatz repetitions.

property norb

The number of spatial orbitals.

to_parameters(*, alpha_alpha_indices=None, alpha_beta_indices=None)[source]

Convert the UCJ operator to a real-valued parameter vector.

If alpha_alpha_indices or alpha_beta_indices is specified, the returned parameter vector will incorporate only the diagonal Coulomb matrix entries corresponding to the given indices, so the original operator will not be recoverable from the parameter vector.

Parameters:
  • alpha_alpha_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the “alpha-alpha” diagonal Coulomb matrices (see the docstring of this class). If not specified, all matrix entries are allowed to be nonzero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error.

  • alpha_beta_indices (list[tuple[int, int]] | None) – Allowed indices for nonzero values of the “alpha-beta” diagonal Coulomb matrices (see the docstring of this class). If not specified, all matrix entries are allowed to be nonzero. This list should contain only upper trianglular indices, i.e., pairs \((i, j)\) where \(i \leq j\). Passing a list with lower triangular indices will raise an error.

Return type:

ndarray

Returns:

The real-valued parameter vector.

Raises:
  • ValueError – alpha_alpha_indices contains lower triangular indices.

  • ValueError – alpha_beta_indices contains lower triangular indices.

to_t_amplitudes(nocc=None)[source]

Convert the UCJ operator to t2 (and possibly t1) amplitudes.

Return type:

ndarray | tuple[ndarray, ndarray]

ffsim.addresses_to_strings(addresses, norb, nelec, concatenate=True, bitstring_type=BitstringType.INT)[source]

Convert state vector addresses to bitstrings.

Example:

import ffsim

norb = 3
nelec = (2, 1)
dim = ffsim.dim(norb, nelec)

strings = ffsim.addresses_to_strings(range(5), norb, nelec)
print(strings)  # prints [11, 19, 35, 13, 21]

strings = ffsim.addresses_to_strings(
    range(5), norb, nelec, bitstring_type=ffsim.BitstringType.STRING
)
print(strings)  # prints ['001011', '010011', '100011', '001101', '010101']

strings = ffsim.addresses_to_strings(
    range(5), norb, nelec, bitstring_type=ffsim.BitstringType.BIT_ARRAY
)
print(strings)
# prints
# [[False False  True False  True  True]
#  [False  True False False  True  True]
#  [ True False False False  True  True]
#  [False False  True  True False  True]
#  [False  True False  True False  True]]
Parameters:
  • addresses (Sequence[int] | ndarray) – The state vector addresses to convert to bitstrings.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • bitstring_type (BitstringType) – The desired type of bitstring output.

  • concatenate (bool) – Whether to concatenate the spin-alpha and spin-beta parts of the bitstrings. If True, then a single list of concatenated bitstrings is returned. The strings are concatenated in the order \(s_b s_a\), that is, the alpha string appears on the right. If False, then two lists are returned, (strings_a, strings_b). Note that the list of alpha strings appears first, that is, on the left. In the spinless case (when nelec is an integer), this argument is ignored.

Returns:

The bitstrings. The type of the output depends on bitstring_type and concatenate.

ffsim.apply_diag_coulomb_evolution(vec, mat, time, norb, nelec, *, orbital_rotation=None, z_representation=False, copy=True)[source]

Apply time evolution by a (rotated) diagonal Coulomb operator.

Applies

\[\mathcal{U} \exp\left(-i t \sum_{\sigma, \tau, i, j} Z^{(\sigma \tau)}_{ij} n_{\sigma, i} n_{\tau, j} / 2\right) \mathcal{U}^\dagger\]

where \(n_{\sigma, i}\) denotes the number operator on orbital \(i\) with spin \(\sigma\), \(Z^{(\sigma \tau)}\) is a real-valued matrix, and \(\mathcal{U}\) is an optional orbital rotation.

Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • mat (ndarray | tuple[ndarray | None, ndarray | None, ndarray | None]) – The diagonal Coulomb matrix \(Z\). You can pass either a single Numpy array specifying the coefficients to use for all spin interactions, or you can pass a tuple of three Numpy arrays specifying independent coefficients for alpha-alpha, alpha-beta, and beta-beta interactions (in that order). If passing a tuple, you can set a tuple element to None to indicate the absence of interactions of that type. The alpha-alpha and beta-beta matrices are assumed to be symmetric, and only their upper triangular entries are used.

  • time (float) – The evolution time.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • orbital_rotation (ndarray | tuple[ndarray | None, ndarray | None] | None) – The optional orbital rotation. You can pass either a single Numpy array specifying the orbital rotation to apply to both spin sectors, or you can pass a pair of Numpy arrays specifying independent orbital rotations for spin alpha and spin beta. If passing a pair, you can use None for one of the values in the pair to indicate that no operation should be applied to that spin sector.

  • z_representation (bool) – Whether the input matrices are in the “Z” representation.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

Returns:

The evolved state vector.

ffsim.apply_fsim_gate(vec, theta, phi, target_orbs, norb, nelec, spin=<Spin.ALPHA_AND_BETA: 3>, *, copy=True)[source]

Apply an fSim gate.

An fSim gate consists of a tunneling interaction followed by a number-number interaction (note the negative sign convention for the angles):

\[\begin{split}\begin{align} \text{fSim}&(\theta, \phi, (p, q)) = \text{NN}(-\phi, (p, q)) \text{T}(-\theta, (p, q)) \\ &= \prod_\sigma \exp\left(-i \phi a^\dagger_{\sigma, p} a_{\sigma, p} a^\dagger_{\sigma, q} a_{\sigma, q}\right) \exp\left(-i \theta (a^\dagger_{\sigma, p} a_{\sigma, q} + a^\dagger_{\sigma, q} a_{\sigma, p})\right) \end{align}\end{split}\]

Under the Jordan-Wigner transform, this gate has the following matrix when applied to neighboring qubits:

\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\theta) & -i \sin(\theta) & 0\\ 0 & -i \sin(\theta) & \cos(\theta) & 0\\ 0 & 0 & 0 & e^{-i \phi} \\ \end{pmatrix}\end{split}\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • theta (float) – The rotation angle for the tunneling interaction.

  • phi (float) – The phase angle for the number-number interaction.

  • target_orbs (tuple[int, int]) – The orbitals (p, q) to interact.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • spin (Spin) –

    Choice of spin sector(s) to act on.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

ffsim.apply_fswap_gate(vec, target_orbs, norb, nelec, spin=<Spin.ALPHA_AND_BETA: 3>, *, copy=True)[source]

Apply an FSWAP gate.

The FSWAP gate swaps two orbitals. It is represented by the operator

\[\text{FSWAP}(p, q) = 1 + a^\dagger_p a_q + a^\dagger_q a_p - a_p^\dagger a_p - a_q^\dagger a_q\]

Under the Jordan-Wigner transform, this gate has the following matrix when applied to neighboring qubits:

\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & -1 \\ \end{pmatrix}\end{split}\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • target_orbs (tuple[int, int]) – The orbitals (p, q) to swap.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • spin (Spin) – Choice of spin sector(s) to act on.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated

      vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated

      vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

ffsim.apply_givens_rotation(vec, theta, target_orbs, norb, nelec, spin=<Spin.ALPHA_AND_BETA: 3>, *, phi=0.0, copy=True)[source]

Apply a Givens rotation gate.

The Givens rotation gate is

\[\text{G}(\theta, \varphi, (p, q)) = \prod_{\sigma} \exp\left(i\varphi a^\dagger_{\sigma, p} a_{\sigma, p}\right) \exp\left(\theta (a^\dagger_{\sigma, p} a_{\sigma, q} - a^\dagger_{\sigma, q} a_{\sigma, p})\right) \exp\left(-i\varphi a^\dagger_{\sigma, p} a_{\sigma, p}\right)\]

Under the Jordan-Wigner transform, this gate has the following matrix when applied to neighboring qubits:

\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\theta) & -e^{-i\varphi}\sin(\theta) & 0\\ 0 & e^{i\varphi}\sin(\theta) & \cos(\theta) & 0\\ 0 & 0 & 0 & 1 \\ \end{pmatrix}\end{split}\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • theta (float) – The rotation angle.

  • target_orbs (tuple[int, int]) – The orbitals (p, q) to rotate.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • spin (Spin) –

    Choice of spin sector(s) to act on.

  • phi (float) – The optional phase angle.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

ffsim.apply_hop_gate(vec, theta, target_orbs, norb, nelec, spin=<Spin.ALPHA_AND_BETA: 3>, *, copy=True)[source]

Apply a hop gate.

A “hop gate” is a Givens rotation gate followed by a number-number interaction with angle pi:

\[\begin{split}\begin{align} \text{Hop}&(\theta, (p, q)) = \text{NN}(\pi, (p, q)) \text{G}(\theta, (p, q)) \\ &= \prod_{\sigma} \exp\left(i \theta a^\dagger_{\sigma, p} a_{\sigma, p} a^\dagger_{\sigma, q} a_{\sigma, q}\right) \exp\left(\theta (a^\dagger_{\sigma, p} a_{\sigma, q} - a^\dagger_{\sigma, q} a_{\sigma, p})\right) \end{align}\end{split}\]

Under the Jordan-Wigner transform, this gate has the following matrix when applied to neighboring qubits:

\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\theta) & -\sin(\theta) & 0\\ 0 & \sin(\theta) & \cos(\theta) & 0\\ 0 & 0 & 0 & -1 \\ \end{pmatrix}\end{split}\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • theta (float) – The rotation angle.

  • target_orbs (tuple[int, int]) – The orbitals (p, q) to interact.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • spin (Spin) –

    Choice of spin sector(s) to act on.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

ffsim.apply_num_interaction(vec, theta, target_orb, norb, nelec, spin=<Spin.ALPHA_AND_BETA: 3>, *, copy=True)[source]

Apply a number interaction gate.

The number interaction gate is

\[\text{N}(\theta, p) = \prod_{\sigma} \exp\left(i \theta a^\dagger_{\sigma, p} a_{\sigma, p}\right)\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • theta (float) – The rotation angle.

  • target_orb (int) – The orbital on which to apply the interaction.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • spin (Spin) –

    Choice of spin sector(s) to act on.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

ffsim.apply_num_num_interaction(vec, theta, target_orbs, norb, nelec, spin=<Spin.ALPHA_AND_BETA: 3>, *, copy=True)[source]

Apply a number-number interaction gate.

The number-number interaction gate is

\[\text{NN}(\theta, (p, q)) = \prod_{\sigma} \exp\left(i \theta a^\dagger_{\sigma, p} a_{\sigma, p} a^\dagger_{\sigma, q} a_{\sigma, q}\right)\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • theta (float) – The rotation angle.

  • target_orbs (tuple[int, int]) – The orbitals (p, q) to interact.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • spin (Spin) –

    Choice of spin sector(s) to act on.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

ffsim.apply_num_op_prod_interaction(vec, theta, target_orbs, norb, nelec, *, copy=True)[source]

Apply interaction gate for product of number operators.

The gate is

\[\text{NP}(\theta, (S_\alpha, S_\beta)) = \exp\left(i \theta \prod_{p \in S_\alpha} a^\dagger_{\alpha, p} a_{\alpha, p} \prod_{p \in S_\beta} a^\dagger_{\beta, p} a_{\beta, p} \right)\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • theta (float) – The rotation angle.

  • target_orbs (tuple[Sequence[int], Sequence[int]]) – A pair of lists of integers giving the orbitals on which to apply the interaction. The first list specifies the alpha orbitals and the second list specifies the beta orbitals.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

ffsim.apply_num_op_sum_evolution(vec, coeffs, time, norb, nelec, *, orbital_rotation=None, copy=True)[source]

Apply time evolution by a (rotated) linear combination of number operators.

Applies

\[\mathcal{U} \exp\left(-i t \sum_{\sigma, i} \lambda^{(\sigma)}_i n_{\sigma, i}\right) \mathcal{U}^\dagger\]

where \(n_{\sigma, i}\) denotes the number operator on orbital \(i\) with spin \(\sigma\), the \(\lambda_i\) are real numbers, and \(\mathcal{U}\) is an optional orbital rotation.

Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • coeffs (ndarray | tuple[ndarray | None, ndarray | None]) – The coefficients of the linear combination. You can pass either a single Numpy array specifying the coefficients to apply to both spin sectors, or you can pass a pair of Numpy arrays specifying independent coefficients for spin alpha and spin beta. If passing a pair, you can use None for one of the values in the pair to indicate that no operation should be applied to that spin sector.

  • time (float) – The evolution time.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • orbital_rotation (ndarray | tuple[ndarray | None, ndarray | None] | None) – The optional orbital rotation. You can pass either a single Numpy array specifying the orbital rotation to apply to both spin sectors, or you can pass a pair of Numpy arrays specifying independent orbital rotations for spin alpha and spin beta. If passing a pair, you can use None for one of the values in the pair to indicate that no operation should be applied to that spin sector.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

Returns:

The evolved state vector.

ffsim.apply_on_site_interaction(vec, theta, target_orb, norb, nelec, *, copy=True)[source]

Apply an on-site interaction gate.

The on-site interaction gate is

\[\text{OS}(\theta, p) = \exp\left(i \theta a^\dagger_{\alpha, p} a_{\alpha, p} a^\dagger_{\beta, p} a_{\beta, p}\right)\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • theta (float) – The rotation angle.

  • target_orb (int) – The orbital on which to apply the interaction.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

ffsim.apply_orbital_rotation(vec, mat, norb, nelec, *, copy=True)[source]

Apply an orbital rotation to a vector.

An orbital rotation maps creation operators as

\[a^\dagger_{\sigma, i} \mapsto \sum_{j} U^{(\sigma)}_{ji} a^\dagger_{\sigma, j}\]

where \(U^{(\sigma)}\) is a unitary matrix representing the action of the orbital rotation on spin sector \(\sigma\). This is equivalent to applying the transformation given by

\[\prod_{\sigma} \exp\left(\sum_{ij} \log(U^{(\sigma)})_{ij} a^\dagger_{\sigma, i} a_{\sigma, j}\right)\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • mat (ndarray | tuple[ndarray | None, ndarray | None]) – The unitary matrix \(U\) describing the orbital rotation. You can pass either a single Numpy array specifying the orbital rotation to apply to both spin sectors, or you can pass a pair of Numpy arrays specifying independent orbital rotations for spin alpha and spin beta. If passing a pair, you can use None for one of the values in the pair to indicate that no operation should be applied to that spin sector.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

Returns:

The rotated vector.

ffsim.apply_tunneling_interaction(vec, theta, target_orbs, norb, nelec, spin=<Spin.ALPHA_AND_BETA: 3>, *, copy=True)[source]

Apply a tunneling interaction gate.

The tunneling interaction gate is

\[\text{T}(\theta, (p, q)) = \prod_\sigma \exp\left(i \theta (a^\dagger_{\sigma, p} a_{\sigma, q} + a^\dagger_{\sigma, q} a_{\sigma, p})\right)\]

Under the Jordan-Wigner transform, this gate has the following matrix when applied to neighboring qubits:

\[\begin{split}\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\theta) & i \sin(\theta) & 0\\ 0 & i \sin(\theta) & \cos(\theta) & 0\\ 0 & 0 & 0 & 1 \\ \end{pmatrix}\end{split}\]
Parameters:
  • vec (ndarray) – The state vector to be transformed.

  • theta (float) – The rotation angle.

  • target_orbs (tuple[int, int]) – The orbitals (p, q) on which to apply the interaction.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • spin (Spin) –

    Choice of spin sector(s) to act on.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

ffsim.apply_unitary(vec, obj, norb, nelec, copy=True)[source]

Apply a unitary transformation to a vector.

Parameters:
  • vec (ndarray) – The vector to apply the unitary transformation to.

  • obj (Any) – The object with a unitary effect.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

Returns:

The transformed vector.

ffsim.approx_eq(obj, other, rtol=1e-05, atol=1e-08)[source]

Return whether two objects are approximately equal.

See the documentation of np.isclose for the interpretation of the tolerance parameters rtol and atol.

Parameters:
  • obj (Any) – The first object.

  • other (Any) – The object to compare to.

  • rtol (float) – Relative numerical tolerance.

  • atol (float) – Absolute numerical tolerance.

Return type:

bool

Returns:

True if the objects are approximately equal up to the specified tolerance, and False otherwise.

ffsim.cre(spin, orb)[source]

Create a fermion.

Parameters:
  • spin (bool) – The spin of the orbital. False = alpha, True = beta.

  • orb (int) – The index of the orbital to act on.

Return type:

FermionAction

ffsim.cre_a(orb)[source]

Create a fermion with spin alpha.

Parameters:

orb (int) – The index of the orbital to act on.

Return type:

FermionAction

ffsim.cre_b(orb)[source]

Create a fermion with spin beta.

Parameters:

orb (int) – The index of the orbital to act on.

Return type:

FermionAction

ffsim.des(spin, orb)[source]

Destroy a fermion.

Parameters:
  • spin (bool) – The spin of the orbital. False = alpha, True = beta.

  • orb (int) – The index of the orbital to act on.

Return type:

FermionAction

ffsim.des_a(orb)[source]

Destroy a fermion with spin alpha.

Parameters:

orb (int) – The index of the orbital to act on.

Return type:

FermionAction

ffsim.des_b(orb)[source]

Destroy a fermion with spin beta.

Parameters:

orb (int) – The index of the orbital to act on.

Return type:

FermionAction

ffsim.diag(obj, norb, nelec)[source]

Return the diagonal entries of the linear operator.

Return type:

float

ffsim.dim(norb, nelec)[source]

Get the dimension of the FCI space.

Parameters:
  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

Return type:

int

Returns:

The dimension of the FCI space.

ffsim.dims(norb, nelec)[source]

Get the dimensions of the FCI space.

Parameters:
  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

Return type:

tuple[int, int]

Returns:

A pair of integers (dim_a, dim_b) representing the dimensions of the alpha- and beta- FCI space.

ffsim.expectation_one_body_power(one_rdm, one_body_tensor, power=1)[source]

Expectation of power of one-body operator w.r.t. a Slater determinant.

A one-body operator \(O\) has the form

\[O = \sum_{pq} M_{pq} a_p^\dagger a_q.\]

This function takes the matrix \(M\) as its first argument. Let \(\lvert \psi \rangle\) be the Slater determinant. Then this function returns the quantity

\[\langle \psi \rvert O^k \lvert \psi \rangle.\]
Note: Unlike most functions in ffsim, the inputs to this function are specified

in terms of spin-orbitals, not spatial orbitals. In other words, the one-rdm and the one-body tensors should have the same shape, and all orbitals are treated on an equal footing. The 1-RDM passed here should not be spin-summed, and the one-body tensors should be expanded when compared to the usual one-body tensors elsewhere in ffsim, i.e., scipy.linalg.block_diag(one_body_tensor, one_body_tensor).

Parameters:
  • one_rdm (ndarray) – The one-body reduced density matrix of the Slater determinant.

  • one_body_tensor (ndarray) – The one-body operator.

  • power (int) – The power.

Return type:

complex

Returns:

The expectation value.

ffsim.expectation_one_body_product(one_rdm, one_body_tensors)[source]

Expectation of product of one-body operators w.r.t. a Slater determinant.

A one-body operator \(O\) has the form

\[O = \sum_{pq} M_{pq} a_p^\dagger a_q.\]

This function takes a list of the matrices \(M\) as its first argument. Let \((O_1, O_2, \dots O_k)\) be the list of one-body operators, and \(\lvert \psi \rangle\) be the Slater determinant. Then this function returns the quantity

\[\langle \psi \rvert O_1 O_2 \dots O_k \lvert \psi \rangle.\]
Note: Unlike most functions in ffsim, the inputs to this function are specified

in terms of spin-orbitals, not spatial orbitals. In other words, the one-rdm and the one-body tensors should have the same shape, and all orbitals are treated on an equal footing. The 1-RDM passed here should not be spin-summed, and the one-body tensors should be expanded when compared to the usual one-body tensors elsewhere in ffsim, i.e., scipy.linalg.block_diag(one_body_tensor, one_body_tensor).

Parameters:
  • one_rdm (ndarray) – The one-body reduced density matrix of the Slater determinant.

  • one_body_tensors (Sequence[ndarray]) – The matrices for the one-body operators.

Return type:

complex

Returns:

The expectation value.

ffsim.fermi_hubbard_1d(norb, tunneling, interaction, *, chemical_potential=0, nearest_neighbor_interaction=0, periodic=False)[source]

One-dimensional Fermi-Hubbard model Hamiltonian.

The Hamiltonian for the one-dimensional Fermi-Hubbard model with \(N\) spatial orbitals is given by

\[H = -t \sum_{\sigma, \braket{pq}} (a^\dagger_{\sigma, p} a_{\sigma, q} + a^\dagger_{\sigma, q} a_{\sigma, p}) + U \sum_p n_{\alpha, p} n_{\beta, p} - \mu \sum_p (n_{\alpha, p} + n_{\beta, p}) + V \sum_{\sigma \tau, \braket{pq}} n_{\sigma, p} n_{\tau, q}\]

where \(n_{\sigma, p} = a_{\sigma, p}^\dagger a_{\sigma, p}\) is the number operator on orbital \(p\) with spin \(\sigma\) and the index \(\braket{pq}\) runs over pairs of orbitals \(p\) and \(q\) that are connected on the line. If periodic boundary conditions are chosen, then the first and last orbitals are connected. More explicitly:

  • For open boundary conditions, \(\braket{pq}\) runs over pairs \((p, p + 1)\) for \(p = 1, \ldots, N - 1\).

  • For periodic boundary conditions, \(\braket{pq}\) runs over pairs \((p, p + 1 \bmod N)\) for \(p = 1, \ldots, N\).

In the case that \(N = 2\), using periodic boundary conditions will cause the connection between the two vertices to be counted twice, forming a “ring with two edges”.

References

Parameters:
  • norb (int) – The number of spatial orbitals \(N\).

  • tunneling (float) – The tunneling amplitude \(t\).

  • interaction (float) – The onsite interaction strength \(U\).

  • chemical_potential (float) – The chemical potential \(\mu\).

  • nearest_neighbor_interaction (float) – The nearest-neighbor interaction strength \(V\).

  • periodic (bool) – Whether to use periodic boundary conditions.

Return type:

FermionOperator

Returns:

The one-dimensional Fermi-Hubbard model Hamiltonian.

ffsim.fermi_hubbard_2d(norb_x, norb_y, tunneling, interaction, *, chemical_potential=0, nearest_neighbor_interaction=0, periodic=False, periodic_x=False, periodic_y=False)[source]

Two-dimensional Fermi-Hubbard model Hamiltonian on a square lattice.

The Hamiltonian for the two-dimensional Fermi-Hubbard model on a square lattice with \(N_x\) columns and \(N_y\) rows is given by

\[H = -t \sum_{\sigma, \braket{pq}} (a^\dagger_{\sigma, p} a_{\sigma, q} + a^\dagger_{\sigma, q} a_{\sigma, p}) + U \sum_p n_{\alpha, p} n_{\beta, p} - \mu \sum_p (n_{\alpha, p} + n_{\beta, p}) + V \sum_{\sigma \tau, \braket{pq}} n_{\sigma, p} n_{\tau, q}\]

where \(n_{\sigma, p} = a_{\sigma, p}^\dagger a_{\sigma, p}\) is the number operator on orbital \(p\) with spin \(\sigma\) and the index \(\braket{pq}\) runs over pairs of orbitals \(p\) and \(q\) that are connected on the lattice. If periodic boundary conditions are chosen, then orbitals in the first and last columns are connected, as are orbitals in the first and last rows, so that the square lattice forms a torus. In the case that one of the dimensions has size 2, using periodic boundary conditions will cause the connection along that dimension to be counted twice.

References

Parameters:
  • norb_x (int) – The number of spatial orbitals in the x-direction \(N_x\).

  • norb_y (int) – The number of spatial orbitals in the y-direction \(N_y\).

  • tunneling (float) – The tunneling amplitude \(t\).

  • interaction (float) – The onsite interaction strength \(U\).

  • chemical_potential (float) – The chemical potential \(\mu\).

  • nearest_neighbor_interaction (float) – The nearest-neighbor interaction strength \(V\).

  • periodic (bool) – Whether to use periodic boundary conditions in all dimensions. This argument overrides the periodic_x and periodic_y arguments.

  • periodic_x (bool) – Whether to use periodic boundary conditions in the X dimension.

  • periodic_y (bool) – Whether to use periodic boundary conditions in the Y dimension.

Return type:

FermionOperator

Returns:

The two-dimensional Fermi-Hubbard model Hamiltonian.

ffsim.fermion_operator(obj)[source]

Return a FermionOperator representing the object.

Parameters:

obj (Any) – The object to convert to a LinearOperator.

Return type:

FermionOperator

Returns:

A FermionOperator representing the object.

ffsim.hartree_fock_state(norb, nelec)[source]

Return the Hartree-Fock state.

Parameters:
  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

Return type:

ndarray

Returns:

The Hartree-Fock state as a state vector.

ffsim.indices_to_strings(indices, norb, nelec, concatenate=True, bitstring_type=BitstringType.STRING)[source]

Convert state vector indices to bitstrings.

Warning

This function is deprecated. Use ffsim.addresses_to_strings instead.

Example:

import ffsim

norb = 3
nelec = (2, 1)
dim = ffsim.dim(norb, nelec)
ffsim.indices_to_strings(range(dim), norb, nelec)
# output:
# ['001011',
#  '010011',
#  '100011',
#  '001101',
#  '010101',
#  '100101',
#  '001110',
#  '010110',
#  '100110']
Parameters:
  • indices (Sequence[int] | ndarray) – The state vector indices to convert to bitstrings.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • bitstring_type (BitstringType) – The desired type of bitstring output.

  • concatenate (bool) – Whether to concatenate the spin-alpha and spin-beta parts of the bitstrings. If True, then a single list of concatenated bitstrings is returned. The strings are concatenated in the order \(s_b s_a\), that is, the alpha string appears on the right. If False, then two lists are returned, (strings_a, strings_b). Note that the list of alpha strings appears first, that is, on the left. In the spinless case (when nelec is an integer), this argument is ignored.

ffsim.init_cache(norb, nelec)[source]

Initialize cached objects.

Call this function to prepare ffsim for performing operations with given values of norb and nelec. Typically there is no need to call this function, but it should be called before benchmarking to avoid counting the cost of initializing cached lookup tables.

Parameters:
  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

Return type:

None

ffsim.linear_operator(obj, norb, nelec)[source]

Return a SciPy LinearOperator representing the object.

Parameters:
  • obj (Any) – The object to convert to a LinearOperator.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

Return type:

LinearOperator

Returns:

A Scipy LinearOperator representing the object.

ffsim.multireference_state(hamiltonian, ansatz_operator, reference_occupations, norb, nelec, root=0)[source]

Compute multireference energy and state.

Parameters:
  • hamiltonian (LinearOperator | SupportsLinearOperator) – The Hamiltonian.

  • ansatz_operator (SupportsApplyUnitary) – The ansatz operator.

  • reference_occupations (Sequence[tuple[Sequence[int], Sequence[int]]]) – The orbital occupations of the reference states.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • root (int) – The index of the desired eigenvector. Defaults to 0, which yields the lowest-energy state.

Return type:

tuple[float, ndarray]

Returns:

The energy of the multireference state, and the state itself.

ffsim.multireference_state_prod(hamiltonian, ansatz_operator, reference_occupations, norb, nelec, root=0, tol=1e-08)[source]

Compute multireference state for a product ansatz operator.

Parameters:
  • hamiltonian (MolecularHamiltonian | SingleFactorizedHamiltonian) – The Hamiltonian.

  • ansatz_operator (tuple[SupportsApplyUnitary, SupportsApplyUnitary]) – The alpha and beta parts of the ansatz operator.

  • reference_occupations (Sequence[tuple[Sequence[int], Sequence[int]]]) – The orbital occupations of the reference states.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • root (int) – The index of the desired eigenvector. Defaults to 0, which yields the lowest-energy state.

  • tol (float) – Numerical tolerance to use for the single factorization of the molecular Hamiltonian. If the input is already a SingleFactorizedHamiltonian, this argument is ignored.

Return type:

tuple[float, ProductStateSum]

Returns:

The energy of the multireference state, and the state itself.

ffsim.number_operator(orb, spin=<Spin.ALPHA_AND_BETA: 3>)[source]

Occupation number operator.

The occupation number operator for orbital \(p\) is defined as

\[n_p = \sum_\sigma a^\dagger_{\sigma, p} a_{\sigma, p}\]
Parameters:
Return type:

FermionOperator

Returns:

The number operator acting on the specified orbital and spin sector(s).

ffsim.one_hot(shape, index, *, dtype=<class 'complex'>)[source]

Return an array of all zeros except for a one at a specified index.

Warning

This function is deprecated. Use ffsim.linalg.one_hot() instead.

Parameters:
  • shape (int | tuple[int, ...]) – The desired shape of the array.

  • index – The index at which to place a one.

Returns:

The one-hot vector.

ffsim.rdm(vec, norb, nelec, rank=1, spin_summed=True, reordered=True, return_lower_ranks=True)[source]

Return the reduced density matrix (RDM) or matrices of a state vector.

Warning

This function is deprecated. Use ffsim.rdms() instead.

The rank 1 RDM is defined as follows:

rdm1[p, q] = ⟨p+ q⟩

The definition of higher-rank RDMs depends on the reordered argument, which defaults to True.

reordered = True

The reordered RDMs are defined as follows:

rdm2[p, q, r, s] = ⟨p+ r+ s q⟩
rdm3[p, q, r, s, t, u] = ⟨p+ r+ t+ u s q⟩
rdm4[p, q, r, s, t, u, v, w] = ⟨p+ r+ t+ v+ w u s q⟩

reordered = False

If reordered is set to False, the RDMs are defined as follows:

rdm2[p, q, r, s] = ⟨p+ q r+ s⟩
rdm3[p, q, r, s, t, u] = ⟨p+ q r+ s t+ u⟩
rdm4[p, q, r, s, t, u, v, w] = ⟨p+ q r+ s t+ u v+ w⟩

Note

Currently, only ranks 1 and 2 are supported.

Parameters:
  • vec (ndarray) – The state vector whose reduced density matrix is desired.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • rank (int) – The rank of the reduced density matrix.

  • spin_summed (bool) – Whether to sum over the spin index.

  • reordered (bool) – Whether to reorder the indices of the reduced density matrix.

  • return_lower_ranks (bool) – Whether to return lower rank RDMs in addition to the specified rank. If True, then this function returns all RDMs up to and including the specified rank, in increasing order of rank. For example, if rank=2 then a tuple (rdm1, rdm2) is returned.

Return type:

ndarray | tuple[ndarray, ...]

Returns:

The reduced density matrix or matrices. If return_lower_ranks is False, then a single matrix is returned. If return_lower_ranks is True, then a rank-length tuple of matrices is returned, containing the RDMs up to the specified rank in increasing order of rank.

ffsim.rdms(vec, norb, nelec, *, rank=1, spin_summed=False, reorder=True)[source]

Return the spin-separated reduced density matrices of a state vector.

The rank 1 RDM is defined as follows:

rdm1[p, q] = ⟨p+ q⟩

The definition of higher-rank RDMs depends on the reorder argument, which defaults to True.

reorder = True

The reordered RDMs are defined as follows:

rdm2[p, q, r, s] = ⟨p+ r+ s q⟩
rdm3[p, q, r, s, t, u] = ⟨p+ r+ t+ u s q⟩
rdm4[p, q, r, s, t, u, v, w] = ⟨p+ r+ t+ v+ w u s q⟩

reorder = False

If reorder is set to False, the RDMs are defined as follows:

rdm2[p, q, r, s] = ⟨p+ q r+ s⟩
rdm3[p, q, r, s, t, u] = ⟨p+ q r+ s t+ u⟩
rdm4[p, q, r, s, t, u, v, w] = ⟨p+ q r+ s t+ u v+ w⟩

Note

Currently, only ranks 1 and 2 are supported.

Parameters:
  • vec (ndarray) – The state vector whose reduced density matrix is desired.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • rank (int) – The rank of the reduced density matrix.

  • spin_summed (bool) – Whether to return the “spin-summed” RDMs.

  • reorder (bool) – Whether to reorder the indices of the reduced density matrix.

Return type:

ndarray | tuple[ndarray, ...]

Returns:

The reduced density matrices. All RDMs up to and including the specified rank are returned, in increasing order of rank. For example, if rank=2 then a tuple (rdm1, rdm2) is returned. The 1-RDMs are: (alpha-alpha, beta-beta). The spin-summed 1-RDM is alpha-alpha + alpha-beta. The 2-RDMs are: (alpha-alpha, alpha-beta, beta-beta). The spin-summed 2-RDM is alpha-alpha + alpha-beta + beta-alpha + beta-beta.

ffsim.sample_slater_determinant(rdm, norb, nelec, *, orbs=None, shots=1, concatenate=True, bitstring_type=BitstringType.STRING, seed=None)[source]

Collect samples of electronic configurations from a Slater determinant.

The Slater determinant is defined by its one-body reduced density matrix (RDM). The sampler uses a determinantal point process to auto-regressively produce uncorrelated samples.

This sampling strategy is known as determinantal point processes <https://arxiv.org/abs/1207.6083>

Parameters:
  • rdm (ndarray | tuple[ndarray, ndarray]) – The one-body reduced density matrix that defines the Slater determinant This is either a single Numpy array specifying the 1-RDM of a spin-polarized system, or a pair of Numpy arrays where each element of the pair contains the 1-RDM for each spin sector.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • shots (int) – The number of bitstrings to sample.

  • concatenate (bool) – Whether to concatenate the spin-alpha and spin-beta parts of the bitstrings. If True, then a single list of concatenated bitstrings is returned. The strings are concatenated in the order \(s_b s_a\), that is, the alpha string appears on the right. If False, then two lists are returned, (strings_a, strings_b). Note that the list of alpha strings appears first, that is, on the left. In the spinless case (when nelec is an integer), this argument is ignored.

  • bitstring_type (BitstringType) – The desired type of bitstring output.

  • seed (Generator | int | None) – A seed to initialize the pseudorandom number generator. Should be a valid input to np.random.default_rng.

Return type:

Sequence[int] | Sequence[str] | ndarray

Returns:

A 2D Numpy array with samples of electronic configurations. Each row is a sample.

ffsim.sample_state_vector(vec, *, norb=None, nelec=None, orbs=None, shots=1, concatenate=True, bitstring_type=BitstringType.STRING, seed=None)[source]

Sample bitstrings from a state vector.

Parameters:
  • vec (ndarray | StateVector) – The state vector to sample from.

  • norb (int | None) – The number of spatial orbitals.

  • nelec (int | tuple[int, int] | None) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

  • orbs (Sequence[int] | tuple[Sequence[int], Sequence[int]] | None) – The spin-orbitals to sample. In the spinless case (when nelec is an integer), this is a list of integers ranging from 0 to norb. In the spinful case, this is a pair of lists of such integers, with the first list storing the spin-alpha orbitals and the second list storing the spin-beta orbitals. If not specified, then all spin-orbitals are sampled.

  • shots (int) – The number of bitstrings to sample.

  • concatenate (bool) – Whether to concatenate the spin-alpha and spin-beta parts of the bitstrings. If True, then a single list of concatenated bitstrings is returned. The strings are concatenated in the order \(s_b s_a\), that is, the alpha string appears on the right. If False, then two lists are returned, (strings_a, strings_b). Note that the list of alpha strings appears first, that is, on the left. In the spinless case (when nelec is an integer), this argument is ignored.

  • bitstring_type (BitstringType) – The desired type of bitstring output.

  • seed (Generator | int | None) – A seed to initialize the pseudorandom number generator. Should be a valid input to np.random.default_rng.

Return type:

list[str] | tuple[list[str], list[str]]

Returns:

The sampled bitstrings, as a list of strings of length shots.

Raises:
  • TypeError – When passing vec as a Numpy array, norb and nelec must be specified.

  • TypeError – When passing vec as a StateVector, norb and nelec must both be None.

ffsim.simulate_qdrift_double_factorized(vec, hamiltonian, time, *, norb, nelec, n_steps=1, symmetric=False, probabilities='norm', one_rdm=None, n_samples=1, seed=None)[source]

Double-factorized Hamiltonian simulation via qDRIFT.

Parameters:
  • vec (ndarray) – The state vector to evolve.

  • hamiltonian (DoubleFactorizedHamiltonian) – The Hamiltonian.

  • time (float) – The evolution time.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • n_steps (int) – The number of Trotter steps.

  • probabilities (str | ndarray) – The sampling method to use, or else an explicit array of probabilities. If specifying a string, the following options are supported: - “norm”: Sample each term with probability proportional to its spectral norm. - “uniform”: Sample each term with uniform probability. - “optimal”: Sample with probabilities optimized for a given initial state. The “optimal” method requires the one-body reduced density matrix of the initial state to be specified. It returns optimal probabilities whenever the initial state is completely characterized by this reduced density matrix, i.e., it is a Slater determinant.

  • one_rdm (ndarray | None) – The one-body reduced density matrix of the initial state.

  • n_samples (int) – The number of qDRIFT trajectories to sample.

  • seed – A seed to initialize the pseudorandom number generator. Should be a valid input to np.random.default_rng.

Return type:

ndarray

Returns:

A Numpy array representing the final state of the simulation. The shape of the array depends on the n_samples argument. If n_samples=1 then it is just a state vector, a one-dimensional array. Otherwise, it is a two-dimensional array of shape (n_samples, dim) where dim is the dimension of the state vector.

ffsim.simulate_trotter_diag_coulomb_split_op(vec, hamiltonian, time, *, norb, nelec, n_steps=1, order=0, copy=True)[source]

Diagonal Coulomb Hamiltonian simulation using split-operator method.

Parameters:
  • vec (ndarray) – The state vector to evolve.

  • hamiltonian (DiagonalCoulombHamiltonian) – The Hamiltonian.

  • time (float) – The evolution time.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • n_steps (int) – The number of Trotter steps.

  • order (int) – The order of the Trotter decomposition.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

Returns:

The final state of the simulation.

ffsim.simulate_trotter_double_factorized(vec, hamiltonian, time, *, norb, nelec, n_steps=1, order=0, copy=True)[source]

Double-factorized Hamiltonian simulation using Trotter-Suzuki formula.

Parameters:
  • vec (ndarray) – The state vector to evolve.

  • hamiltonian (DoubleFactorizedHamiltonian) – The Hamiltonian.

  • time (float) – The evolution time.

  • norb (int) – The number of spatial orbitals.

  • nelec (tuple[int, int]) – The number of alpha and beta electrons.

  • n_steps (int) – The number of Trotter steps.

  • order (int) – The order of the Trotter decomposition.

  • copy (bool) –

    Whether to copy the vector before operating on it.

    • If copy=True then this function always returns a newly allocated vector and the original vector is left untouched.

    • If copy=False then this function may still return a newly allocated vector, but the original vector may have its data overwritten. It is also possible that the original vector is returned, modified in-place.

Return type:

ndarray

Returns:

The final state of the simulation.

ffsim.slater_determinant(norb, occupied_orbitals, orbital_rotation=None)[source]

Return a Slater determinant.

A Slater determinant is a state of the form

\[\mathcal{U} \lvert x \rangle,\]

where \(\mathcal{U}\) is an orbital rotation and \(\lvert x \rangle\) is an electronic configuration.

Parameters:
  • norb (int) – The number of spatial orbitals.

  • occupied_orbitals (Sequence[int] | tuple[Sequence[int], Sequence[int]]) – The occupied orbitals in the electronic configuration. This is either a list of integers specifying spinless orbitals, or a pair of lists, where the first list specifies the spin alpha orbitals and the second list specifies the spin beta orbitals.

  • orbital_rotation (ndarray | tuple[ndarray | None, ndarray | None] | None) – The optional orbital rotation. You can pass either a single Numpy array specifying the orbital rotation to apply to both spin sectors, or you can pass a pair of Numpy arrays specifying independent orbital rotations for spin alpha and spin beta. If passing a pair, you can use None for one of the values in the pair to indicate that no operation should be applied to that spin sector.

Return type:

ndarray

Returns:

The Slater determinant as a state vector.

ffsim.slater_determinant_rdm(norb, occupied_orbitals, orbital_rotation=None, rank=1, spin_summed=True)[source]

Return the reduced density matrix of a Slater determinant.

Warning

This function is deprecated. Use ffsim.slater_determinant_rdms() instead.

Note

Currently, only rank 1 is supported.

Parameters:
  • norb (int) – The number of spatial orbitals.

  • occupied_orbitals (tuple[Sequence[int], Sequence[int]]) – The occupied orbitals in the electronic configuration. This is a pair of lists of integers, where the first list specifies the spin alpha orbitals and the second list specifies the spin beta orbitals.

  • orbital_rotation (ndarray | tuple[ndarray | None, ndarray | None] | None) – The optional orbital rotation. You can pass either a single Numpy array specifying the orbital rotation to apply to both spin sectors, or you can pass a pair of Numpy arrays specifying independent orbital rotations for spin alpha and spin beta. If passing a pair, you can use None for one of the values in the pair to indicate that no operation should be applied to that spin sector.

  • rank (int) – The rank of the reduced density matrix. I.e., rank 1 corresponds to the one-particle RDM, rank 2 corresponds to the 2-particle RDM, etc.

  • spin_summed (bool) – Whether to sum over the spin index.

Return type:

ndarray

Returns:

The reduced density matrix of the Slater determinant.

ffsim.slater_determinant_rdms(norb, occupied_orbitals, orbital_rotation=None, *, rank=1)[source]

Return the reduced density matrices of a Slater determinant.

Note

Currently, only rank 1 is supported.

Parameters:
  • norb (int) – The number of spatial orbitals.

  • occupied_orbitals (Sequence[int] | tuple[Sequence[int], Sequence[int]]) – The occupied orbitals in the electronic configuration. This is either a list of integers specifying spinless orbitals, or a pair of lists, where the first list specifies the spin alpha orbitals and the second list specifies the spin beta orbitals.

  • orbital_rotation (ndarray | tuple[ndarray | None, ndarray | None] | None) – The optional orbital rotation. You can pass either a single Numpy array specifying the orbital rotation to apply to both spin sectors, or you can pass a pair of Numpy arrays specifying independent orbital rotations for spin alpha and spin beta. If passing a pair, you can use None for one of the values in the pair to indicate that no operation should be applied to that spin sector.

  • rank (int) – The rank of the reduced density matrix. I.e., rank 1 corresponds to the one-particle RDM, rank 2 corresponds to the 2-particle RDM, etc.

Return type:

ndarray

Returns:

The reduced density matrices of the Slater determinant. All RDMs up to and including the specified rank are returned, in increasing order of rank. For example, if rank=2 then a tuple (rdm1, rdm2) is returned. The representation of an RDM depends on whether occupied_orbitals is a sequence of integers (spinless case), or a pair of such sequences (spinful case). In the spinless case, the full RDM is returned. In the spinful case, each RDM is represented as a stacked Numpy array of sub-RDMs. For example, the 1-RDMs are: (alpha-alpha, alpha-beta), and the 2-RDMs are: (alpha-alpha, alpha-beta, beta-beta).

ffsim.spin_square(fcivec, norb, nelec)[source]

Expectation value of spin squared operator on a state vector.

ffsim.strings_to_addresses(strings, norb, nelec)[source]

Convert bitstrings to state vector addresses.

Example:

import numpy as np

import ffsim

norb = 3
nelec = (2, 1)
dim = ffsim.dim(norb, nelec)

addresses = ffsim.strings_to_addresses(
    [
        0b001011,
        0b010101,
        0b100101,
        0b010110,
        0b100110,
    ],
    norb,
    nelec,
)
print(addresses)  # prints [0 4 5 7 8]

addresses = ffsim.strings_to_addresses(
    [
        "001011",
        "010101",
        "100101",
        "010110",
        "100110",
    ],
    norb,
    nelec,
)
print(addresses)  # prints [0 4 5 7 8]

addresses = ffsim.strings_to_addresses(
    np.array(
        [
            [False, False, True, False, True, True],
            [False, True, False, True, False, True],
            [True, False, False, True, False, True],
            [False, True, False, True, True, False],
            [True, False, False, True, True, False],
        ]
    ),
    norb,
    nelec,
)
print(addresses)  # prints [0 4 5 7 8]
Parameters:
  • strings (Sequence[int] | Sequence[str] | ndarray) – The bitstrings to convert to state vector addresses. Can be a list of strings, a list of integers, or a Numpy array of bits.

  • norb (int) – The number of spatial orbitals.

  • nelec (int | tuple[int, int]) – Either a single integer representing the number of fermions for a spinless system, or a pair of integers storing the numbers of spin alpha and spin beta fermions.

Return type:

ndarray

Returns:

The state vector addresses, as a Numpy array of integers.

ffsim.strings_to_indices(strings, norb, nelec)[source]

Convert bitstrings to state vector indices. :rtype: ndarray

Warning

This function is deprecated. Use ffsim.strings_to_addresses instead.

Example:

import ffsim

norb = 3
nelec = (2, 1)
dim = ffsim.dim(norb, nelec)
ffsim.strings_to_indices(
    [
        "001011",
        "010011",
        "100011",
        "001101",
        "010101",
        "100101",
        "001110",
        "010110",
        "100110",
    ],
    norb,
    nelec,
)
# output:
# array([0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=int32)
ffsim.trace(obj, norb, nelec)[source]

Return the trace of the linear operator.

Return type:

float