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
— TypeMajoranaReg{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
— Methodbitstring_probability(reg::MajoranaReg, bit_string::BitStr)
The probability to measure a given bit_string
when measuring reg
FLOYao.covariance_matrix
— Methodcovariance_matrix(reg::MajoranaReg)
The covariance matrix
\[ M_{pq} = \frac{i}{2} ⟨Ω|U^†[γ_p,γ_q]U|Ω⟩\]
of a FLO state $U|Ω⟩$.
FLOYao.fast_add!
— Methodfast_add!(A::AbstractMatrix, B::SparseMatrixCSC)
Fast implementation of A .+= B
for sparse B
.
FLOYao.fast_overlap
— Methodfast_overlap(y::AbstractVecOrMat, A::SparseMatrixCSC, x::AbstractVecOrMat)
Fast implementation of tr(y' * A * x)
for sparse A
.
FLOYao.kron2majoranaindices
— Methodkron2majoranaindices(k::KronBlock)
Get the indices of majorana operators from a kronecker product of pauli operators
FLOYao.majorana2arrayreg
— Methodmajorana2arrayreg(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
— Methodmajorana_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
— Methodmajoranasquares2qubitbasis(H::AbstractMatrix)
Converts an $2n×2n$ Majorana hamiltonian H
into the full $2^n×2^n$ hamiltonian in the qubit basis.
FLOYao.one_state!
— Methodone_state!(reg::MajoranaReg)
Put reg
into the all ones state
FLOYao.one_state
— Methodone_state([T=Float64,] n)
Create a Majorana register on n
qubits in the all one state $|1 ⋯ 1⟩$ with storage type T
.
FLOYao.paulibasis2majoranasquares
— Functionpaulibasis2majoranasquares(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
— Methodpaulibasis2qubitop(P::AbstractVector)
Converts an operator to in the pauli basis to a matrix in the computational basis. Inverse to qubit2paulibasis
.
FLOYao.product_state!
— Methodproduct_state!(reg::MajoranaReg, bit_str::BitStr)
Put reg
into the product state described by bit_str
FLOYao.product_state
— Methodproduct_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
— Methodqubit2majoranaevolution(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
— Methodqubit2paulibasis(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
— Methodrand_state([Float64,] n)
Create a Haar random MajoranaReg
on n
qubits.
FLOYao.random_orthogonal_matrix
— Methodrandom_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
— Methodrandom_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
— Methodreducedmat(::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
— Functionsample!(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
arianvemat
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 measureids=sortperm(locs)
: The sorting permutation forlocs
. You don't need to pass this, but precomputing it can make this fasterrng=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
— Methodyaoham2majoranasquares(::Type{T}=Float64, yaoham::AbstracBlock{2})
Convert a hamiltonian written as a YaoBlock into the corresponding $2n×2n$ majorana hamiltonian.
FLOYao.zero_state!
— Methodzero_state!(reg::MajoranaReg)
Put reg
into the computational zero state
FLOYao.zero_state
— Methodzero_state([T=Float64,] n)
Create a Majorana register on n
qubits in the vacuum state $|Ω⟩$ with storage type T
.
FLOYao.zero_state_like
— Methodzero_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
— Methodexpect(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
— Methodfidelity(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!
— Methodmeasure!([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 methodNoPostProcess()
(the default) will collapse the state to the measurement outcome state.ResetTo(bit_str)
will reset the state to the product state specified bybit_str
reg::MajoranaReg
: The quantum registerrng::Random.GLOBAL_RNG
: The RNG to use
YaoAPI.measure
— Methodmeasure(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 registerlocs
: The list of qubits to measure. Defaults to all qubits.nshots=1
: The number of samples to takerng=Random.GLOBAL_RNG
: The random number generator to use