Fermionic package

Piquasso package for Fermionic quantum computation.

Note

This feature is still experimental.

Basic notations

Let \(f_k\) and \(f_k^\dagger\) denote the Dirac operators. These fulfill the CAR algebra, i.e.,

\[\begin{split}\{ f_i, f_j^\dagger \} &= I \delta_{ij}, \\\\ \{ f_i, f_j \} &= \{ f_i^\dagger, f_j^\dagger \} = 0.\end{split}\]

Let us define \(\mathbf{f}\) as

\[\mathbf{f} = [f_1^\dagger, \dots, f_d^\dagger, f_1, \dots, f_d].\]

The Majorana operators are defined as

\[\begin{split}x_k &:= f_k + f_k^\dagger, \\\\ p_k &:= -i (f_k - f_k^\dagger),\end{split}\]

where \(f_k\) and \(f_k^\dagger\) denote the Dirac operators.

\(\mathbf{m}\) denotes the vector of Majorana operators, i.e.,

(1)\[\mathbf{m} := [x_1, \dots, x_d, p_1, \dots, p_d].\]

Fermionic instructions

Extra instructions specific for Fermionic quantum computing.

class ParentHamiltonian(hamiltonian)

Bases: Preparation

Prepares the fermionic Gaussian state with a specified parent Hamiltonian.

The density matrix is of the form

\[\rho = \frac{e^{\hat{H}}}{\operatorname{Tr} e^{\hat{H}}},\]

where \(\hat{H}\) is the parent Hamiltonian and has the form

\[\begin{split}\hat{H} &= \mathbf{f}^\dagger H \mathbf{f}, \\\\ H &= \begin{bmatrix} - \overline{A} & B \\ - \overline{B} & A \end{bmatrix}. \\\\\end{split}\]

Here, \(A\) is self-adjoint and \(B\) is skew-symmetric.

class GaussianHamiltonian(hamiltonian)

Bases: Gate

Applies a fermionic Gaussian transformation using its quadratic Hamiltonian.

The gate unitary is of the form

\[U = e^{i \hat{H}},\]

where

\[\begin{split}\hat{H} &= \mathbf{f} H \mathbf{f}^\dagger, \\\\ H &= \begin{bmatrix} A & -\overline{B} \\ B & -\overline{A} \end{bmatrix}.\end{split}\]

Here, \(A\) is self-adjoint and \(B\) is skew-symmetric.

class ControlledPhase(phi: float)

Bases: Gate

Controlled-phase gate.

The controlled-phase gate is defined via the unitary operator

\[\text{CPhase}_{ij} (\phi) = \exp \left ( i \phi n_i n_j \right ).\]

Note

This is a non-linear gate, therefore it couldn’t be used with GaussianSimulator.

Note

This is analoguous to the CrossKerr gate in the photonic setting.

Parameters:

phi (float) – The controlled-phase angle.

class IsingXX(phi: float)

Bases: Gate

Ising XX coupling gate.

The Ising XX gate is defined via the unitary operator

\[\text{XX}_{ij} (\phi) = \exp \left ( i \phi X \otimes X \right ) = \cos \phi I + i \sin \phi (X \otimes X).\]

Considering a two-mode system with Majorana operators \(m_1, m_2, m_3, m_4\), \(X \otimes X\) can also be written as

\[X \otimes X = -i m_2 m_3.\]
Parameters:

phi (float) – The rotation angle.

Fermionic Gaussian simulations

This is a package for Fermionic Linear Optics (FLO) or Fermionic Gaussian states.

class GaussianSimulator(d: int | None = None, config: Config | None = None, connector: BaseConnector | None = None)

Bases: BuiltinSimulator

Fermionic Gaussian simulator.

Example usage:

passive_hamiltonian = np.array([[1, 2j, 3j], [-2j, 5, 6], [-3j, 6, 7]])

U = expm(1j * passive_hamiltonian)

state_vector = [1, 0, 1]

with pq.Program() as program:
    pq.Q() | pq.StateVector(state_vector)

    pq.Q() | pq.Interferometer(U)

simulator = pq.fermionic.GaussianSimulator(d=3, connector=connector)

state = simulator.execute(program).state
Supported preparations:

Vacuum, StateVector.

Supported gates:

Interferometer, Beamsplitter, Phaseshifter, GaussianHamiltonian.

create_initial_state(d=None)

Creates an initial state with no instructions executed.

Note

This is not necessarily a vacuum state.

Returns:

The initial state of the simulation.

Return type:

State

execute(program: Program, shots: int | None = 1, initial_state: State | None = None) Result

Executes the specified program.

Parameters:
  • program (Program) – The program to execute.

  • initial_state (State, optional) – A state to execute the instructions on. Defaults to the state created by create_initial_state().

  • shots (int, optional) – The number of times the program should execute. If it is None, the simulator will execute the program once, returning the exact probability distribution instead of samples. Defaults to 1.

Raises:

InvalidParameter – When shots is not a positive integer or not None.

Returns:

The result of the simulation containing the resulting state and samples if any measurement is specified in program.

Return type:

Result

execute_instructions(instructions: List[Instruction], initial_state: State | None = None, shots: int | None = 1) Result

Executes the specified instruction list.

Parameters:
  • instructions (List[Instruction]) – The instructions to execute.

  • initial_state (State, optional) – A state to execute the instructions on. Defaults to the state created by create_initial_state().

  • shots (int, optional) – The number of times the program should be execute. If it is None, the simulator will execute the program once, returning the exact probability distribution instead of samples. Defaults to 1.

Raises:
  • InvalidParameter – When shots is not a positive integer or not None.

  • InvalidSimulation – When the number of modes cannot be inferred and d was not provided during simulator initialization.

Returns:

The result of the simulation containing the resulting state and samples if any measurement is specified in instructions.

Return type:

Result

validate(program: Program) None

Validates the specified program.

Raises:
  • InvalidInstruction – When invalid instructions are defined in the program.

  • InvalidSimulation – When the instructions are valid, but the simulator couldn’t execute the specified program.

Parameters:

program (Program) – The program to validate.

class GaussianState(d: int, connector: BaseConnector, config: Config | None = None)

Bases: State

A fermionic Gaussian state.

copy() State

Returns an exact copy of this state.

Returns:

An exact copy of this state.

Return type:

State

property correlation_matrix

The correlation matrix in the Dirac basis.

The correlation matrix is defined by

\[\begin{split}\Gamma := \begin{bmatrix} \Gamma^{f^\dagger f} & \Gamma^{f^\dagger f^\dagger} \\ \Gamma^{f f} & \Gamma^{f f^\dagger} \end{bmatrix},\end{split}\]

where \(\Gamma_{i,j}^{f^\dagger f} = \langle f_i^\dagger f_j \rangle\) and \(\Gamma_{i,j}^{f f} = \langle f_i f_j \rangle\).

By CAR, we know that \(\Gamma_{i,j}^{f^\dagger f} = - \overline{\Gamma_{i,j}^{f f^\dagger }}\) and \(\Gamma_{i,j}^{f f} = I - \overline{\Gamma_{i,j}^{f^\dagger f^\dagger }}\)

The correlation matrix is a self-adjoint matrix.

property covariance_matrix: np.ndarray

The covariance matrix.

A fermionic Gaussian state can be fully characterized by its covariance matrix defined by

\[\Sigma_{ij} := -i \operatorname{Tr} (\rho [\mathbf{m}_i, \mathbf{m}_j]) / 2,\]

where \(\mathbf{m}\) is defined by Eq. (1). The covariance matrix is a real-valued, skew-symmetric matrix.

Returns:

The covariance matrix.

Return type:

np.ndarray

property d

The number of modes.

property density_matrix: np.ndarray

Density matrix in the lexicographic ordering.

When applicable, the density matrix is just

\[\rho = e^{\hat{H}} / \operatorname{Tr} e^{\hat{H}},\]

where \(\hat{H}\) is the parent hamiltonian (see get_parent_hamiltonian()) given by

\[\begin{split}\hat{H} = \mathbf{f}^\dagger H \mathbf{f}, \\\\ H = \begin{bmatrix} A & -\overline{B} \\ B & -\overline{A} \end{bmatrix}.\end{split}\]

where \(A^\dagger = A\) and \(B^T = - B\).

Note

The density matrix is returned in matrix form here. This will probably change in the future to tensor form.

property fock_probabilities: np.ndarray

Returns the particle detection probabilities.

Note

The ordering of the Fock basis is increasing with particle numbers, and in each particle number conserving subspace, lexicographic ordering is used.

Returns:

The particle detection probabilities.

Return type:

numpy.ndarray

get_majorana_monomial_expectation_value(indices)

Calculates Majorana monomial expectation values using Wick’s theorem.

The monomial indices are understood in the xxpp-ordering.

Parameters:

indices – Indices of the Majorana operators in any order with possible with possible multiplicities.

get_parent_hamiltonian()

Calculates the parent Hamiltonian.

When the correlation matrix is not singular, the density matrix is

\[\rho = e^{\hat{H}} / \operatorname{Tr} e^{\hat{H}},\]

where \(\hat{H}\) is the parent hamiltonian (see get_parent_hamiltonian()) given by

\[ \begin{align}\begin{aligned}\begin{split}\hat{H} = \mathbf{f}^\dagger H \mathbf{f}, \\\\\end{split}\\\begin{split}H = \begin{bmatrix} A & -\overline{B} \\ B & -\overline{A} \end{bmatrix}.\end{split}\end{aligned}\end{align} \]

where \(A^\dagger = A\) and \(B^T = - B\).

Raises:

PiquassoException – When the correlation matrix is singular.

get_parity_operator_expectation_value()

Calculates the expectation value of the parity operator.

The parity operator is defined as

\[P = i^d m_1 \dots m_{2d} = i^d x_1 \dots x_d p_1 \dots p_d.\]
get_particle_detection_probability(occupation_number: np.ndarray) float

Returns the particle number detection probability using the occupation number specified as a parameter.

Parameters:

occupation_number (tuple) – Tuple of natural numbers representing the number of particles in each mode.

Returns:

The probability of detection.

Return type:

float

property maj_correlation_matrix

The correlation matrix in the Majorana operator basis.

mean_particle_numbers(modes)

Returns the mean particle numbers on the specified modes.

overlap(other)

Calculates the overlap between two fermionic Gaussian states.

The overlap is the Hilbert-Schmidt inner product of the density matrices.

reduced(modes)

Reduces the state to a subsystem on the specified modes.

validate()

Validates the state.

Fermionic Fock space-based simulators

This is a package for Fock space-based simulations of fermionic states.

class PureFockState(d: int, connector: BaseConnector, config: Config | None = None)

Bases: State

A fermionic pure Fock state.

copy() State

Returns an exact copy of this state.

Returns:

An exact copy of this state.

Return type:

State

property covariance_matrix: np.ndarray

The covariance matrix.

The covariance matrix is defined by

\[\Sigma_{ij} := -i \operatorname{Tr} (\rho [\mathbf{m}_i, \mathbf{m}_j]) / 2,\]

where \(\mathbf{m}\) is defined by Eq. (1). The covariance matrix is a real-valued, skew-symmetric matrix.

Note

The covariance matrix does not fully characterize this state in general, only if it is a Gaussian state. For manipulating Gaussian states, visit GaussianState.

Returns:

The covariance matrix.

Return type:

np.ndarray

property d

The number of modes.

property density_matrix: np.ndarray

The density matrix of the state.

Warning

The primary ordering of the Fock basis is by number of particles, and the secondary is anti-lexicographic.

Example for 3 modes:

\[\ket{000}, \ket{100}, \ket{010}, \ket{001}, \ket{200}, \ket{110}, \ket{101}, \ket{020}, \ket{011}, \ket{002}, \dots\]

This is in contrast with density_matrix(), where the primary ordering is lexicographic.

Returns:

The density matrix.

Return type:

np.ndarray

property fock_probabilities: np.ndarray

Returns the particle detection probabilities.

Note

The ordering of the Fock basis is increasing with particle numbers, and in each particle number conserving subspace, lexicographic ordering is used.

Returns:

The particle detection probabilities.

Return type:

numpy.ndarray

property fock_probabilities_map: dict
get_particle_detection_probability(occupation_number)

Returns the particle number detection probability using the occupation number specified as a parameter.

Parameters:

occupation_number (tuple) – Tuple of natural numbers representing the number of particles in each mode.

Returns:

The probability of detection.

Return type:

float

property norm: float
property state_vector

The state vector of the quantum state.

Warning

The primary ordering of the Fock basis is by number of particles, and the secondary is anti-lexicographic.

Example for 3 modes:

\[\ket{000}, \ket{100}, \ket{010}, \ket{001}, \ket{200}, \ket{110}, \ket{101}, \ket{020}, \ket{011}, \ket{002}, \dots\]

This is in contrast with density_matrix(), where the primary ordering is lexicographic.

validate()

Validates the state.

class PureFockSimulator(d: int | None = None, config: Config | None = None, connector: BaseConnector | None = None)

Bases: BuiltinSimulator

Fermionic pure Fock state simulator.

Example usage:

U = scipy.stats.unitary_group.rvs(4)

with pq.Program() as program:
    pq.Q() | pq.StateVector([0, 0, 1, 1]) / np.sqrt(2)
    pq.Q() | pq.StateVector([1, 1, 0, 0]) / np.sqrt(2)
    pq.Q() | pq.Interferometer(U)

simulator = pq.fermionic.PureFockSimulator(
    d=4, config=pq.Config(cutoff=4 + 1)
)

state = simulator.execute(program).state
Supported preparations:

Vacuum, StateVector.

Supported gates:

Interferometer.

create_initial_state(d=None)

Creates an initial state with no instructions executed.

Note

This is not necessarily a vacuum state.

Returns:

The initial state of the simulation.

Return type:

State

execute(program: Program, shots: int | None = 1, initial_state: State | None = None) Result

Executes the specified program.

Parameters:
  • program (Program) – The program to execute.

  • initial_state (State, optional) – A state to execute the instructions on. Defaults to the state created by create_initial_state().

  • shots (int, optional) – The number of times the program should execute. If it is None, the simulator will execute the program once, returning the exact probability distribution instead of samples. Defaults to 1.

Raises:

InvalidParameter – When shots is not a positive integer or not None.

Returns:

The result of the simulation containing the resulting state and samples if any measurement is specified in program.

Return type:

Result

execute_instructions(instructions: List[Instruction], initial_state: State | None = None, shots: int | None = 1) Result

Executes the specified instruction list.

Parameters:
  • instructions (List[Instruction]) – The instructions to execute.

  • initial_state (State, optional) – A state to execute the instructions on. Defaults to the state created by create_initial_state().

  • shots (int, optional) – The number of times the program should be execute. If it is None, the simulator will execute the program once, returning the exact probability distribution instead of samples. Defaults to 1.

Raises:
  • InvalidParameter – When shots is not a positive integer or not None.

  • InvalidSimulation – When the number of modes cannot be inferred and d was not provided during simulator initialization.

Returns:

The result of the simulation containing the resulting state and samples if any measurement is specified in instructions.

Return type:

Result

validate(program: Program) None

Validates the specified program.

Raises:
  • InvalidInstruction – When invalid instructions are defined in the program.

  • InvalidSimulation – When the instructions are valid, but the simulator couldn’t execute the specified program.

Parameters:

program (Program) – The program to validate.