ffsim.qiskit

Code that uses Qiskit, e.g. for constructing quantum circuits.

class ffsim.qiskit.DiagCoulombEvolutionJW(norb, mat, time, *, z_representation=False, label=None)[source]

Bases: Gate

Diagonal Coulomb evolution under the Jordan-Wigner transformation.

The diagonal Coulomb evolution gate has the unitary

exp(itσ,τ,i,jZij(στ)nσ,inτ,j/2)

where nσ,i denotes the number operator on orbital i with spin σ, Z(στ) is a real-valued matrix.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(norb, mat, time, *, z_representation=False, label=None)[source]

Create new diagonal Coulomb evolution gate.

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

  • 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.

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

  • label (str | None) – The label of the gate.

inverse()[source]

Inverse gate.

class ffsim.qiskit.DiagCoulombEvolutionSpinlessJW(norb, mat, time, *, label=None)[source]

Bases: Gate

Spinless diagonal Coulomb evolution under the Jordan-Wigner transformation.

The spinless diagonal Coulomb evolution gate has the unitary

exp(iti,jZijninj/2)

where ni denotes the number operator on orbital i and Z is a real symmetric matrix.

__init__(norb, mat, time, *, label=None)[source]

Create new diagonal Coulomb evolution gate.

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

  • mat (ndarray) – The diagonal Coulomb matrix Z. It is assumed to be symmetric, and only its upper triangular entries are used.

  • time (float) – The evolution time.

  • label (str | None) – The label of the gate.

inverse()[source]

Inverse gate.

class ffsim.qiskit.DropNegligible(atol=1e-08)[source]

Bases: TransformationPass

Drop gates with negligible effects.

__init__(atol=1e-08)[source]

Initialize the transpiler pass.

Parameters:

atol (float) – Absolute numerical tolerance for determining whether a gate’s effect is negligible.

run(dag)[source]

Run a pass on the DAGCircuit. This is implemented by the pass developer.

Parameters:

dag (DAGCircuit) – the dag on which the pass is run.

Raises:

NotImplementedError – when this is left unimplemented for a pass.

Return type:

DAGCircuit

class ffsim.qiskit.FfsimSampler(*, default_shots=1024, norb=None, nelec=None, global_depolarizing=0.0, seed=None)[source]

Bases: BaseSamplerV2

Implementation of the Qiskit Sampler primitive backed by ffsim.

__init__(*, default_shots=1024, norb=None, nelec=None, global_depolarizing=0.0, seed=None)[source]

Initialize the ffsim Sampler.

FfsimSampler is an implementation of the Qiskit Sampler Primitive specialized for fermionic quantum circuits. It does not support arbitrary circuits, but only those with a certain structure. Generally speaking, there are two ways to construct a circuit that FfsimSampler can simulate:

1. Use gates from the ffsim.qiskit module. The circuit should begin with a state preparation gate (one whose name begins with the prefix Prepare, such as PrepareHartreeFockJW) that acts on all of the qubits. Next, a number of unitary gates from the ffsim.qiskit module are applied. Finally, measurement gates must only occur at the end of the circuit.

2. Use Qiskit gates. The circuit should begin with some X gates. Next, a number of unitary gates are applied. The following unitary gates are supported: [CPhaseGate, PhaseGate, RZGate, RZZGate, XXPlusYYGate]. XXPlusYYGates must be applied to adjacent qubits. Finally, measurement gates must only occur at the end of the circuit.

When simulating spinful circuits constructed from Qiskit gates, you should pass the norb and nelec arguments to the FfsimSampler initialization. Otherwise, a spinless simulation will be performed, which is less efficient.

Parameters:
  • default_shots (int) – The default shots to use if not specified during run.

  • 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.

  • global_depolarizing (float) – Depolarizing probability for a noisy simulation. Specifies the probability of sampling from the uniform distribution instead of the state vector.

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

run(pubs, *, shots=None)[source]

Run and collect samples from each pub.

Parameters:
  • pubs (Iterable[Union[QuantumCircuit, Tuple[QuantumCircuit], Tuple[QuantumCircuit, Mapping[Union[Parameter, str, Tuple[Union[Parameter, str], ...]], Union[Buffer, _SupportsArray[dtype[Any]], _NestedSequence[_SupportsArray[dtype[Any]]], bool, int, float, complex, str, bytes, _NestedSequence[bool | int | float | complex | str | bytes]]]], Tuple[QuantumCircuit, Mapping[Union[Parameter, str, Tuple[Union[Parameter, str], ...]], Union[Buffer, _SupportsArray[dtype[Any]], _NestedSequence[_SupportsArray[dtype[Any]]], bool, int, float, complex, str, bytes, _NestedSequence[bool | int | float | complex | str | bytes]]], Optional[Integral]]]]) – An iterable of pub-like objects. For example, a list of circuits or tuples (circuit, parameter_values).

  • shots (int | None) – The total number of shots to sample for each sampler pub that does not specify its own shots. If None, the primitive’s default shots value will be used, which can vary by implementation.

Return type:

PrimitiveJob[PrimitiveResult[SamplerPubResult]]

Returns:

The job object of Sampler’s result.

class ffsim.qiskit.GivensAnsatzOpJW(givens_ansatz_op, *, label=None)[source]

Bases: Gate

Givens rotation ansatz operator under the Jordan-Wigner transformation.

See ffsim.GivensAnsatzOp for a description of this gate’s unitary.

__init__(givens_ansatz_op, *, label=None)[source]

Create a new Givens ansatz operator gate.

Parameters:
  • givens_ansatz_op (GivensAnsatzOp) – The Givens rotation ansatz operator.

  • label (str | None) – The label of the gate.

class ffsim.qiskit.GivensAnsatzOpSpinlessJW(givens_ansatz_op, *, label=None)[source]

Bases: Gate

Spinless Givens rotation ansatz operator under the Jordan-Wigner transformation.

Like GivensAnsatzOpJW but only acts on a single spin species.

__init__(givens_ansatz_op, *, label=None)[source]

Create a new Givens ansatz operator gate.

Parameters:
  • givens_ansatz_op (GivensAnsatzOp) – The Givens rotation ansatz operator.

  • label (str | None) – The label of the gate.

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

Bases: TransformationPass

Merge consecutive orbital rotation gates.

run(dag)[source]

Run a pass on the DAGCircuit. This is implemented by the pass developer.

Parameters:

dag (DAGCircuit) – the dag on which the pass is run.

Raises:

NotImplementedError – when this is left unimplemented for a pass.

Return type:

DAGCircuit

class ffsim.qiskit.NumNumAnsatzOpSpinBalancedJW(num_num_ansatz_op, *, label=None)[source]

Bases: Gate

Spin-balanced number-number ansatz under the Jordan-Wigner transformation.

See NumNumAnsatzOpSpinBalanced for a description of this gate’s unitary.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(num_num_ansatz_op, *, label=None)[source]

Create a new number-number ansatz operator gate.

Parameters:
  • num_num_ansatz_op (NumNumAnsatzOpSpinBalanced) – The number-number ansatz operator.

  • label (str | None) – The label of the gate.

class ffsim.qiskit.NumOpSumEvolutionJW(norb, coeffs, time, *, label=None)[source]

Bases: Gate

Number operator sum evolution under the Jordan-Wigner transformation.

The number operator sum evolution gate has the unitary

exp(itσ,iλi(σ)nσ,i)

where nσ,i denotes the number operator on orbital i with spin σ and the λi are real numbers.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(norb, coeffs, time, *, label=None)[source]

Create new number operator sum evolution gate.

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

  • 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.

  • label (str | None) – The label of the gate.

inverse()[source]

Inverse gate.

class ffsim.qiskit.NumOpSumEvolutionSpinlessJW(norb, coeffs, time, *, label=None)[source]

Bases: Gate

Spinless number operator sum evolution under the Jordan-Wigner transformation.

The spinless number operator sum evolution gate has the unitary

exp(itiλini)

where ni denotes the number operator on orbital i and the λi are real numbers.

__init__(norb, coeffs, time, *, label=None)[source]

Create new number operator sum evolution gate.

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

  • coeffs (ndarray) – The coefficients of the linear combination.

  • time (float) – The evolution time.

  • label (str | None) – The label of the gate.

inverse()[source]

Inverse gate.

class ffsim.qiskit.OrbitalRotationJW(norb, orbital_rotation, *, label=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Bases: Gate

Orbital rotation under the Jordan-Wigner transformation.

An orbital rotation maps creation operators as

aσ,ijUjiaσ,j

where U is a unitary matrix. This is equivalent to applying the transformation given by

σexp(ijlog(U)ijaσ,iaσ,j)

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(norb, orbital_rotation, *, label=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Create new orbital rotation gate.

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

  • orbital_rotation (ndarray | tuple[ndarray | None, ndarray | None]) – 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.

  • label (str | None) – The label of the gate.

  • validate (bool) – Whether to check that the input orbital rotation(s) is unitary and raise an error if it isn’t.

  • rtol (float) – Relative numerical tolerance for input validation.

  • atol (float) – Absolute numerical tolerance for input validation.

Raises:

ValueError – The input matrix is not unitary.

inverse()[source]

Inverse gate.

class ffsim.qiskit.OrbitalRotationSpinlessJW(norb, orbital_rotation, *, label=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Bases: Gate

Orbital rotation under the Jordan-Wigner transformation, spinless version.

Like OrbitalRotationJW but only acts on a single spin species.

__init__(norb, orbital_rotation, *, label=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Create new orbital rotation gate.

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

  • orbital_rotation (ndarray) – The orbital rotation.

  • label (str | None) – The label of the gate.

  • validate (bool) – Whether to check that the input orbital rotation(s) is unitary and raise an error if it isn’t.

  • rtol (float) – Relative numerical tolerance for input validation.

  • atol (float) – Absolute numerical tolerance for input validation.

Raises:

ValueError – The input matrix is not unitary.

inverse()[source]

Inverse gate.

ffsim.qiskit.PRE_INIT = <qiskit.transpiler.passmanager.PassManager object>

Pass manager recommended for the Qiskit transpiler pre_init stage.

See pre_init_passes() for a description of the transpiler passes included in this pass manager.

class ffsim.qiskit.PrepareHartreeFockJW(norb, nelec, label=None)[source]

Bases: Gate

Gate that prepares the Hartree-Fock state (under JWT) from the all zeros state.

This gate assumes the Jordan-Wigner transformation (JWT).

This gate is meant to be applied to the all zeros state. It decomposes simply as a sequence of X gates that prepares the Hartree-Fock electronic configuration.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(norb, nelec, label=None)[source]

Create new Hartree-Fock state preparation gate.

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

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

  • label (str | None) – The label of the gate.

class ffsim.qiskit.PrepareHartreeFockSpinlessJW(norb, nelec, label=None)[source]

Bases: Gate

Prepare the Hartree-Fock state (under JWT) from the zero state, spinless.

Like PrepareHartreeFockJW but only acts on a single spin species.

__init__(norb, nelec, label=None)[source]

Create new Hartree-Fock state preparation gate.

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

  • nelec (int) – The number of electrons.

  • label (str | None) – The label of the gate.

class ffsim.qiskit.PrepareSlaterDeterminantJW(norb, occupied_orbitals, orbital_rotation=None, *, label=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Bases: Gate

Gate that prepares a Slater determinant (under JWT) from the all zeros state.

This gate assumes the Jordan-Wigner transformation (JWT).

A Slater determinant is a state of the form

U|x,

where U is an orbital rotation and |x is an electronic configuration (computational basis state). The reason this gate exists (when OrbitalRotationJW already exists) is that the preparation of a Slater determinant has a more optimized circuit than a generic orbital rotation.

This gate is meant to be applied to the all zeros state. Its behavior when applied to any other state is not guaranteed. The global phase of the prepared state may be arbitrary.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

Reference: arXiv:1711.05395

__init__(norb, occupied_orbitals, orbital_rotation=None, *, label=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Create new Slater determinant preparation gate.

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

  • occupied_orbitals (tuple[Sequence[int], Sequence[int]]) – The occupied orbitals in the electonic 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.

  • label (str | None) – The label of the gate.

  • validate (bool) – Whether to check that the input orbital rotation(s) is unitary and raise an error if it isn’t.

  • rtol (float) – Relative numerical tolerance for input validation.

  • atol (float) – Absolute numerical tolerance for input validation.

Raises:

ValueError – The input orbital rotation matrix is not unitary.

class ffsim.qiskit.PrepareSlaterDeterminantSpinlessJW(norb, occupied_orbitals, orbital_rotation=None, *, label=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Bases: Gate

Prepare a Slater determinant (under JWT) from the zero state, spinless version.

Like PrepareSlaterDeterminantJW but only acts on a single spin species.

__init__(norb, occupied_orbitals, orbital_rotation=None, *, label=None, validate=True, rtol=1e-05, atol=1e-08)[source]

Create new Slater determinant preparation gate.

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

  • occupied_orbitals (Sequence[int]) – The occupied orbitals in the electonic configuration.

  • orbital_rotation (ndarray | None) – The optional orbital rotation.

  • label (str | None) – The label of the gate.

  • validate (bool) – Whether to check that the input orbital rotation(s) is unitary and raise an error if it isn’t.

  • rtol (float) – Relative numerical tolerance for input validation.

  • atol (float) – Absolute numerical tolerance for input validation.

Raises:

ValueError – The input orbital rotation matrix is not unitary.

class ffsim.qiskit.SimulateTrotterDiagCoulombSplitOpJW(hamiltonian, time, *, n_steps=1, order=0, label=None)[source]

Bases: Gate

Split operator Trotter evolution of diagonal Coulomb Hamiltonian, Jordan-Wigner.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(hamiltonian, time, *, n_steps=1, order=0, label=None)[source]

Create diagonal Coulomb split-operator Trotter evolution gate.

Parameters:
  • norb – The number of spatial orbitals.

  • hamiltonian (DiagonalCoulombHamiltonian) – The Hamiltonian.

  • time (float) – The evolution time.

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

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

  • label (str | None) – The label of the gate.

class ffsim.qiskit.SimulateTrotterDoubleFactorizedJW(hamiltonian, time, *, n_steps=1, order=0, label=None)[source]

Bases: Gate

Trotter time evolution of double-factorized Hamiltonian, Jordan-Wigner.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(hamiltonian, time, *, n_steps=1, order=0, label=None)[source]

Create double-factorized Trotter evolution gate.

Parameters:
  • norb – The number of spatial orbitals.

  • hamiltonian (DoubleFactorizedHamiltonian) – The Hamiltonian.

  • time (float) – The evolution time.

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

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

  • label (str | None) – The label of the gate.

class ffsim.qiskit.UCJOpSpinBalancedJW(ucj_op, *, label=None)[source]

Bases: Gate

Spin-balanced UCJ operator under the Jordan-Wigner transformation.

See ffsim.UCJOpSpinBalanced for a description of this gate’s unitary.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(ucj_op, *, label=None)[source]

Create a new spin-balanced unitary cluster Jastrow (UCJ) gate.

Parameters:
  • ucj_op (UCJOpSpinBalanced) – The UCJ operator.

  • label (str | None) – The label of the gate.

class ffsim.qiskit.UCJOpSpinUnbalancedJW(ucj_op, *, label=None)[source]

Bases: Gate

Spin-unbalanced UCJ operator under the Jordan-Wigner transformation.

See ffsim.UCJOpSpinUnbalanced for a description of this gate’s unitary.

This gate assumes that qubits are ordered such that the first norb qubits correspond to the alpha orbitals and the last norb qubits correspond to the beta orbitals.

__init__(ucj_op, *, label=None)[source]

Create a new spin-unbalanced unitary cluster Jastrow (UCJ) gate.

Parameters:
  • ucj_op (UCJOpSpinUnbalanced) – The UCJ operator.

  • label (str | None) – The label of the gate.

class ffsim.qiskit.UCJOpSpinlessJW(ucj_op, *, label=None)[source]

Bases: Gate

Spinless UCJ operator under the Jordan-Wigner transformation.

See ffsim.UCJOpSpinless for a description of this gate’s unitary.

__init__(ucj_op, *, label=None)[source]

Create a new spinless unitary cluster Jastrow (UCJ) gate.

Parameters:
  • ucj_op (UCJOpSpinless) – The UCJ operator.

  • label (str | None) – The label of the gate.

ffsim.qiskit.ffsim_vec_to_qiskit_vec(vec, norb, nelec)[source]

Convert an ffsim state vector to a Qiskit state vector.

Parameters:
  • vec (ndarray) – A state vector in ffsim/PySCF format. It should be a one-dimensional vector of length comb(norb, n_alpha) * comb(norb, n_beta).

  • 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

ffsim.qiskit.final_state_vector(circuit, norb=None, nelec=None)[source]

Return the final state vector of a fermionic quantum circuit.

Parameters:
  • 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.

  • circuit (QuantumCircuit) – The circuit composed of fermionic gates.

Return type:

StateVector

Returns:

The final state vector that results from applying the circuit to the vacuum state.

ffsim.qiskit.jordan_wigner(op, norb=None)[source]

Jordan-Wigner transformation.

Transform a fermion operator to a qubit operator using the Jordan-Wigner transformation. The Jordan-Wigner transformation maps fermionic annihilation operators to qubits as follows:

ap12(Xp+iYp)Z1Zp1

In the transformed operator, the first norb qubits represent spin-up (alpha) orbitals, and the latter norb qubits represent spin-down (beta) orbitals. As a result of this convention, the qubit index that an orbital is mapped to depends on the total number of spatial orbitals. By default, the total number of spatial orbitals is automatically determined by the largest-index orbital present in the operator, but you can manually specify the number using the norb argument.

Parameters:
  • op (FermionOperator) – The fermion operator to transform.

  • norb (int | None) – The total number of spatial orbitals. If not specified, it is determined by the largest-index orbital present in the operator.

Return type:

SparsePauliOp

Returns:

The qubit operator as a Qiskit SparsePauliOp.

Raises:
  • ValueError – Number of spatial orbitals was negative.

  • ValueError – Number of spatial orbitals was fewer than the number detected in the operator.

ffsim.qiskit.pre_init_passes()[source]

Yield transpiler passes recommended for the Qiskit transpiler pre_init stage.

The following transpiler passes are yielded: :rtype: Iterator[BasePass]

ffsim.qiskit.qiskit_vec_to_ffsim_vec(vec, norb, nelec)[source]

Convert a Qiskit state vector to an ffsim state vector.

Parameters:
  • vec (ndarray) – A state vector in Qiskit format. It should be a one-dimensional vector of length 2 ** (2 * norb).

  • 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