FLOYao

FLOYao.FLOYaoModule

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

source

Installation

FLOYao can be simply installed from the REPL via

pkg> add FLOYao

Quickstart

First import FLOYao and Yao

using FLOYao, Yao

# output

then build a (here somewhat arbitrary) circuit consisting only of Supported gates

nq = 4
θ = π/8
circuit = chain(nq)

push!(circuit, put(nq, 3=>Rz(0.5)))

xxg1 = kron(nq, 1 => X, 2 => X)
rg = rot(xxg1, θ)
push!(circuit, rg)  

xxg2 = kron(nq, 2 => X, 3 => Z, 4 => X)
rg = rot(xxg2, θ)
push!(circuit, rg)  
push!(circuit, put(nq, 3=>Rz(0.5)))
push!(circuit, put(nq, 1=>Z))

xxg3 = kron(nq, 2 => X, 3 => X)
rg = rot(xxg3, θ)

circuit

and define an observable that is a sum of squares of Majorana operators

hamiltonian = xxg1 + xxg2 + xxg3 + kron(nq, 2=>Z) + kron(nq, 3=>Z)

and finally create a register in the computational zero state via

reg = FLOYao.zero_state(nq)

# output
MajoranaReg{Float64} with 4 qubits:
 1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  1.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  1.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  1.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  1.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  1.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  1.0

Applying the circuit to the register works then exactly the same way as for a normal ArrayReg register:

apply(reg, circuit)

# output
MajoranaReg{Float64} with 4 qubits:
 -1.0  -0.0                 -0.0                 …  -0.0                 -0.0
 -0.0  -0.9238795325112867   0.3826834323650898     -0.0                 -0.0
  0.0   0.3826834323650898   0.9238795325112867      0.0                  0.0
  0.0   0.0                  0.0                     0.3826834323650898   0.0
  0.0   0.0                  0.0                     0.0                  0.0
  0.0   0.0                  0.0                 …   0.0                  0.0
  0.0   0.0                  0.0                     0.9238795325112867   0.0
  0.0   0.0                  0.0                     0.0                  1.0

and the same goes for expectation values of observables

expect(hamiltonian, reg => circuit)

# output
1.8535533905932737

or even gradients of these expectation values with respect to the circuit parameters

state_grad, params_grad = expect'(hamiltonian, reg => circuit)

# output
MajoranaReg{Float64}(4) => [0.0, -0.3535533905932738, -0.3535533905932738, 0.0]

Contents