`FLOYao.FLOYao`

— ModuleA Yao.jl backend to efficiently simulate fermionic linear optics (FLO) circuits based on Classical simulation of noninteracting-fermion quantum circuits and Disorder-assisted error correction in Majorana chains. FLO circuits are a class of quantum circuits that are closely related to non-interacting fermions and can be efficiently simulated on classical computers, similar to the way Clifford circuits can be efficiently classically simulated, as is done in YaoClifford.jl.

The goal of `FLOYao.jl`

is that if you have code written in `Yao.jl`

that only uses FLO gates and other primitives that are efficiently simulatable in polynomial time and space, that you can simply replace your `AbstractArrayReg`

with a `MajoranaReg`

and run exactly the same simulation, with the same code but exponentially faster.

A brief introduction to fermionic linear optics circuits is found in the Documentation and a more in-depth introduction in e.g. the two papers linked above.

`FLOYao.MajoranaReg`

— Type```
MajoranaReg{T} <: AbstractRegister{2}
MajoranaReg(state::AbstractMatrix{T<:Real})
```

A register holding the "state" of a Majorana operators when propagating through a FLO circuit as a `2n×2n`

matrix.

**Warning**

The `MajoranaReg`

constructor will not initialize the `state`

matrix. It is recommended to use `FLOYao.zero_state`

or `FLOYao.product_state`

to produce your initial state.

`FLOYao.areconsecutive`

— MethodTests if all entries in `locs`

are consecutive

`FLOYao.bitstring_probability`

— Method`bitstring_probability(reg::MajoranaReg, bit_string::BitStr)`

The probability to measure a given `bit_string`

when measuring `reg`

`FLOYao.covariance_matrix`

— Method`covariance_matrix(reg::MajoranaReg)`

The covariance matrix

\[ M_{pq} = \frac{i}{2} ⟨Ω|U^†[γ_p,γ_q]U|Ω⟩\]

of a FLO state $U|Ω⟩$.

`FLOYao.fast_add!`

— Method`fast_add!(A::AbstractMatrix, B::SparseMatrixCSC)`

Fast implementation of `A .+= B`

for sparse `B`

.

`FLOYao.fast_overlap`

— Method`fast_overlap(y::AbstractVecOrMat, A::SparseMatrixCSC, x::AbstractVecOrMat)`

Fast implementation of `tr(y' * A * x)`

for sparse `A`

.

`FLOYao.kron2majoranaindices`

— Method`kron2majoranaindices(k::KronBlock)`

Get the indices of majorana operators from a kronecker product of pauli operators

`FLOYao.majorana2arrayreg`

— Method`majorana2arrayreg(reg::MajoranaReg)`

Converts a `2n×2n`

MajoranaReg `reg`

into a `2^n`

ArrayReg.

**Note**

This implementation is not very clever and should mainly be used for debugging purposes with small numbers of qubits. It pipes a random state $|ψ⟩$ through the projector $U|Ω⟩⟨Ω|U^†$ which may give inaccurate results if $⟨ψ|U|ψ⟩$ is very small.

`FLOYao.majorana_expect`

— Method`majorana_expect(block::AbstractMatrix, locs, reg::MajoranaReg)`

Calculate `⟨reg|block|reg⟩`

where `block`

is a hamiltonian written as the coefficients in a sum of squares of Majorana operators and `reg`

a MajoranaReg.

`FLOYao.majoranaop`

— MethodMajorana op on `n`

Majorana sites for orbital `ψ`

`FLOYao.majoranaop`

— MethodMajorana operator in a system with `n`

on site Majorana site `i`

`FLOYao.majoranasquares2qubitbasis`

— Method`majoranasquares2qubitbasis(H::AbstractMatrix)`

Converts an $2n×2n$ Majorana hamiltonian `H`

into the full $2^n×2^n$ hamiltonian in the qubit basis.

`FLOYao.one_state!`

— Method`one_state!(reg::MajoranaReg)`

Put `reg`

into the all ones state

`FLOYao.one_state`

— Method`one_state([T=Float64,] n)`

Create a Majorana register on `n`

qubits in the all one state $|1 ⋯ 1⟩$ with storage type `T`

.

`FLOYao.paulibasis2majoranasquares`

— Function`paulibasis2majoranasquares(P::AbstractVector, locs=1:log4(length(P)))`

Convert an operator written in the Pauli basis as a $4^n$-element vector to the corresponding $2n×2n$ matrix of coefficients of products of two Majorana operators.

Throws a `NonFLOException`

if `P`

contains terms that are not corresponding to the product of two Majorana operators.

`FLOYao.paulibasis2qubitop`

— Method`paulibasis2qubitop(P::AbstractVector)`

Converts an operator to in the pauli basis to a matrix in the computational basis. Inverse to `qubit2paulibasis`

.

`FLOYao.product_state!`

— Method`product_state!(reg::MajoranaReg, bit_str::BitStr)`

Put `reg`

into the product state described by `bit_str`

`FLOYao.product_state`

— Method```
product_state([T=Float64,] bit_str::DitStr{2})
product_state([T=Float64,] bit_configs::AbstractVector)
product_state([T=Float64,] nbits::Int, val::Int)
```

Create an `MajoranaReg`

of a product state.

The state can be specified as a bit string, as an array of Integers or Booleans or with `nbits`

and `val`

.

`FLOYao.qubit2majoranaevolution`

— Method`qubit2majoranaevolution(U::AbstractMatrix, locs)`

Turns a $n$ qubit unitary `U`

on the $n$ qubits in `locs`

into the corresponding $SO(2n×2n)$ matrix for the evolution of the Majorana operators.

`FLOYao.qubit2paulibasis`

— Method`qubit2paulibasis(A::AbstractMatrix)`

Converts a $2^n×2^n$ matrix `A`

in the standard qubit basis into a $4^n$ vector representing the same operator in the Pauli basis.

The ordering is as follows: Let $σ^0 = I, σ^1 = X, σ^2 = Y$ and $σ^3 = Z$.

**Todo**

Creating the dense pauli tensor product via `kron`

and inner product via `dot`

is much slower than neccessary, since the pauli tensor product matrix is very sparse. Much faster would be to compute the inner product directly.

`FLOYao.rand_state`

— Method`rand_state([Float64,] n)`

Create a Haar random `MajoranaReg`

on `n`

qubits.

`FLOYao.random_orthogonal_matrix`

— Method`random_orthogonal_matrix([::Type{T}=Float64,] n)`

Generate a Haar random matrix in $O(n)$ with element type `T`

using the algorithm described in How to generate random matrices from the classical compact groups

`FLOYao.random_unit_vector`

— Method`random_unit_vector([Float64, ] n, N=n)`

Generate a uniformly random vector on the `n`

-sphere embedded in ℝ^N and return it and the sign of its first entry.

`FLOYao.reducedmat`

— Method`reducedmat(::Type{T}, k::KronBlock)`

Matrix representation of `k`

with only the qubits `k`

acts on non-trivially in the tensor product. (As opposed to Yao.mat(k) which gives the full 2^n×2^n matrix)

`FLOYao.sample`

— Function`sample!(covmat, locs=1:size(covmat,1)÷2, ids=sortperm(locs), rng=GLOBAL_RNG)`

Take a computational basis state sample from a FLO state with given `cov`

arianve`mat`

rix

**Arguments**

`covmat`

: The 2n×2n covariance matrix $M_{ij} = i ⟨ψ|γ_i γ_j|ψ⟩ - i δ_{ij}$. This matrix will be overwritten by the function!`locs=1:size(covmat,1)÷2`

: The list of qubits to measure`ids=sortperm(locs)`

: The sorting permutation for`locs`

. You don't need to pass this, but precomputing it can make this faster`rng=Random.GLOBAL_RNG`

: The random number generator to use for sampling.

**Warning**

This function works inplace on the covmat argument to avoid allocations. If you need multiple samples from the same covmat, make sure to pass a copy in.

`FLOYao.update_covariance_matrix!`

— MethodUpdates the covariance matrix `M`

, given that the `i`

th qubit was measured in the state `ni`

with probability `pi`

.

**Warning**

After this procedure only the entries M[p,q] with 2i-1 < p < q will be correct. This is sufficient to calculate measurement probabilities for j > i.

`FLOYao.yaoham2majoranasquares`

— Method`yaoham2majoranasquares(::Type{T}=Float64, yaoham::AbstracBlock{2})`

Convert a hamiltonian written as a YaoBlock into the corresponding $2n×2n$ majorana hamiltonian.

`FLOYao.zero_state!`

— Method`zero_state!(reg::MajoranaReg)`

Put `reg`

into the computational zero state

`FLOYao.zero_state`

— Method`zero_state([T=Float64,] n)`

Create a Majorana register on `n`

qubits in the vacuum state $|Ω⟩$ with storage type `T`

.

`FLOYao.zero_state_like`

— Method`zero_state_like(reg::AbstractRegister)`

Create a Majorana register in the zero state with the same element type and number of qubits as `reg`

.

`YaoAPI.expect`

— Method```
expect(op::AbstractBlock, reg::MajoranaReg)
expect(op::AbstractBlock, (reg => circuit)::Pair{<:MajoranaReg,<:AbstractBlock})
```

Get the expectation value of an operator, the second parameter can be a register `reg`

or a pair of input register and circuit `reg => circuit`

.

```
expect'(op::AbstractBlock, reg => circuit::) -> Pair{<:MajoranaReg,<:AbstractVector}
expect'(op::AbstractBlock, reg::MajoranaReg) -> MajoranaReg
```

Obtain the gradient with respect to registers and circuit parameters. For pair input, the second return value is a pair of `gψ => gparams`

, with `gψ`

the gradient of input state and `gparams`

the gradients of circuit parameters. For register input, the return value is a register.

`YaoAPI.fidelity`

— Method`fidelity(reg1::MajoranaReg, reg2::MajoranaReg)`

The fidelity $|⟨ψ|φ⟩|$ between the FLO states $|ψ⟩$ and $|φ⟩$ defined by `reg1`

and `reg2`

.

This definition differs from the standard definition $|⟨φ|ψ⟩|²$ by a square root, but is consistent with the one used in `Yao.jl`

Computing gradients of the fidelity via `fidelity'(pair_or_reg1, pair_or_reg2)`

is not yet supported for `MajoranaReg`

s.

`YaoAPI.measure!`

— Method`measure!([postprocess::Union{NoPostProcess, ResetTo},] reg::MajoranaReg; rng=Random.GLOBAL_RNG)`

Measure a Majorana `reg`

ister in the computational basis and return the resulting `BitStr`

.

**Arguments**

`postprocess`

: Is the post processing method`NoPostProcess()`

(the default) will collapse the state to the measurement outcome state.`ResetTo(bit_str)`

will reset the state to the product state specified by`bit_str`

`reg::MajoranaReg`

: The quantum register`rng::Random.GLOBAL_RNG`

: The RNG to use

`YaoAPI.measure`

— Method`measure(reg::MajoranaReg[, locs]; nshots=1, rng=Random.GLOBAL_RNG) -> Vector{BitStr}`

Measure a MajoranaReg and return the results as a vector of `BitStr`

ings. This is a cheating version of `measure!`

that does not need to recompute the `reg`

for each new sample and also does not alter it.

**Arguments**

`reg::MajoranaReg`

: The state register`locs`

: The list of qubits to measure. Defaults to all qubits.`nshots=1`

: The number of samples to take`rng=Random.GLOBAL_RNG`

: The random number generator to use