Skip to content

Commit

Permalink
Added support for TimeEvolution gates
Browse files Browse the repository at this point in the history
  • Loading branch information
jlbosse committed Jul 20, 2023
1 parent dc227ce commit 35754dc
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FLOYao"
uuid = "6d9310a3-f1d0-41b7-8edb-11c1cf57cd2d"
authors = ["janlukas.bosse <[email protected]> and contributors"]
version = "1.3.0"
version = "1.4.0"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
3 changes: 2 additions & 1 deletion docs/src/features/supported_gates.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ The following gates are FLO gates and supported by `FLOYao.jl`:
| `RotationGate{⋯,⋯,ZGate}` | The only single qubit rotation gate since $R_x(θ)γ_i R_x(-θ)$ is not a linear combination of Majorana operators for all Majorana operators. Similar for $R_y$ |
| `PauliKronBlock` | A kronecker product of Pauli operators s.t. that first and last operator are either $X$ or $Y$ and all operators in between are $Z$. |
| `RotationGate{⋯,⋯,PauliKronBlock}` | A rotation gate with generator as in the last line. |
| `KronBlock{⋯,⋯,RotationGate{⋯}}` | Kronecker products of supported Rotation gates (i.e. those that are generated by supported `PauliKronBlock`s) |
| `KronBlock{⋯,⋯,RotationGate{⋯}}` | Kronecker products of supported Rotation gates (i.e. those that are generated by supported `PauliKronBlock`s) |
| `TimeEvolution` | Time evolution with FLO hamiltonians, i.e. sums of `PauliKronBlock`s |
| `AbstractMatrix` | Unless the gate type is already explicitely implemented or know to not be a FLO gate, `FLOYao` will try to automatically convert the gate matrix in the qubit basis to a matrix in the Majorana basis. But note that this is fairly slow (although still poly-time instead of exp-time) |


Expand Down
4 changes: 4 additions & 0 deletions src/FLOYao.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ using Yao

export MajoranaReg

const PauliGate = Union{I2Gate,XGate,YGate,ZGate}
const PauliKronBlock = KronBlock{2,N,<:NTuple{N,PauliGate}} where {N}
const RGate = RotationGate{2,<:Real,<:PauliKronBlock}

include("utils.jl")
include("majorana_reg.jl")
include("instruct.jl")
Expand Down
16 changes: 13 additions & 3 deletions src/apply_composite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,18 @@ function YaoBlocks.unsafe_apply!(reg::MajoranaReg, k::KronBlock)
return reg
end

const PauliGate = Union{I2Gate,XGate,YGate,ZGate}
const PauliKronBlock = KronBlock{2,N,<:NTuple{N,PauliGate}} where {N}
# Defined in FLOYao.jl
# const PauliGate = Union{I2Gate,XGate,YGate,ZGate}
# const PauliKronBlock = KronBlock{2,N,<:NTuple{N,PauliGate}} where {N}
function YaoBlocks.unsafe_apply!(reg::MajoranaReg, k::PauliKronBlock)
i1, i2 = kron2majoranaindices(k)
reg.state[i1,:] .*= -1
reg.state[i2,:] .*= -1
return reg
end

const RGate = RotationGate{2,<:Real,<:PauliKronBlock}
# Defined in FLOYao.jl
# const RGate = RotationGate{2,<:Real,<:PauliKronBlock}
function YaoBlocks.unsafe_apply!(reg::MajoranaReg, b::RGate)
i1, i2 = kron2majoranaindices(b.block)
s, c = sincos(b.theta)
Expand Down Expand Up @@ -133,3 +135,11 @@ for G in [:X, :Y, :Z, :T, :Tdag]
return reg
end
end

# Time-Evolution block specialisations
# ------------------------------------
function YaoBlocks.unsafe_apply!(reg::MajoranaReg, b::TimeEvolution)
H = yaoham2majoranasquares(b.H)
reg.state .= exp(b.dt .* H) * reg.state
return reg
end
14 changes: 12 additions & 2 deletions src/auto_diff.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,24 @@ function Yao.AD.backward_params!(st::Tuple{<:MajoranaReg,<:MajoranaReg},
return nothing
end

function Yao.AD.backward_params!(st::Tuple{<:MajoranaReg,<:MajoranaReg},
block::TimeEvolution, collector)
out, outδ = st
ham = block.H
majoranaham = yaoham2majoranasquares(ham)
g = outδ.state (majoranaham * out.state) / 2
pushfirst!(collector, g)
return nothing
end

function Yao.AD.apply_back(st::Tuple{<:MajoranaReg,<:MajoranaReg}, block::AbstractBlock)
paramsδ = []
in, inδ = Yao.AD.apply_back!(st, block, paramsδ)
(in, inδ), paramsδ
return (in, inδ), paramsδ
end

function Yao.AD.apply_back!(st::Tuple{<:MajoranaReg,<:MajoranaReg},
block::PutBlock{2,<:Any,BT},
block::Union{PutBlock{2,<:Any,BT},TimeEvolution{2,<:Any,BT}},
collector) where {BT}
out, outδ = st
adjblock = block'
Expand Down
23 changes: 20 additions & 3 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ end

kron2majoranaindices(k::PutBlock{2,1,ZGate}) = (2k.locs[1]-1, 2k.locs[1])

# TODO: Currently all logic is duplicated in `yaoham2majoransquares(, ::Add)`
# and all the other methods to make for fast building of the the sparse
# Hamiltonian. Is there a better way of first collecting all the entries
# with coefficients in a dict and create the actual hamiltonian last?

"""
yaoham2majoranasquares(::Type{T}=Float64, yaoham::AbstracBlock{2})
Expand All @@ -249,9 +254,7 @@ function yaoham2majoranasquares(::Type{T}, yaoham::Add{2}) where {T<:Real}
ham = zeros(T, 2nqubits(yaoham), 2nqubits(yaoham))
for k in yaoham
if k isa Scale
i1, i2 = kron2majoranaindices(k.content)
ham[i1,i2] += 2k.alpha
ham[i2,i1] -= 2k.alpha
ham += k.alpha * yaoham2majoranasquares(T, k.content)
elseif k isa KronBlock
i1, i2 = kron2majoranaindices(k)
ham[i1,i2] += 2
Expand All @@ -262,6 +265,11 @@ function yaoham2majoranasquares(::Type{T}, yaoham::Add{2}) where {T<:Real}
i1, i2 = kron2majoranaindices(k)
ham[i1,i2] += 2
ham[i2,i1] -= 2
elseif k isa PutBlock{2,<:Any,<:PauliKronBlock}
areconsecutive(k.locs) || throw(NonFLOException("$(k.content) contains terms that are not the product of two Majoranas"))
i1, i2 = 2 * (minimum(k.locs) - 1) .+ kron2majoranaindices(k.content)
ham[i1,i2] += 2
ham[i2,i1] -= 2
else
throw(NonFLOException("$k not recognized as a square of Majorana operators"))
end
Expand All @@ -285,6 +293,15 @@ function yaoham2majoranasquares(::Type{T}, yaoham::PutBlock{2,1,ZGate}) where {T
return ham
end

function yaoham2majoranasquares(::Type{T}, yaoham::PutBlock{2,N,<:PauliKronBlock}) where {T<:Real, N}
areconsecutive(yaoham.locs) || throw(NonFLOException("$(yaoham.content) contains terms that are not the product of two Majoranas"))
ham = spzeros(T, 2nqubits(yaoham), 2nqubits(yaoham))
i1, i2 = 2 * (minimum(yaoham.locs) - 1) .+ kron2majoranaindices(yaoham.content)
ham[i1,i2] = 2
ham[i2,i1] = -2
return ham
end

function yaoham2majoranasquares(::Type{T}, yaoham::Scale) where {T<:Real}
return yaoham.alpha * yaoham2majoranasquares(T, yaoham.content)
end
Expand Down
44 changes: 43 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ import FLOYao: majorana2arrayreg, NonFLOException
@const_gate FSWAP::ComplexF64 = [1 0 0 0; 0 0 1 0; 0 1 0 0; 0 0 0 -1]
@const_gate ManualX::ComplexF64 = [0 1; 1 0]

function ising_hamiltonian(nq, J, h)
U = map(1:nq-1) do i
J * kron(nq, i => X, i+1 => X)
end |> sum

T = map(1:nq) do i
h * kron(nq, i => Z)
end |> sum

hamiltonian = T + U

return hamiltonian
end

@testset "MajoranaRegister" begin
nq = 2
mreg = FLOYao.zero_state(nq)
Expand Down Expand Up @@ -180,6 +194,21 @@ end
@test fidelity(majorana2arrayreg(mreg), areg) 1.
end

@testset "TimeEvolution" begin
nq = 5
J = 1.5
h = -1.
hamiltonian = ising_hamiltonian(nq, J, h)
ising_evolution = time_evolve(hamiltonian, 1.)

mreg = FLOYao.zero_state(nq)
areg = zero_state(nq)

mreg |> ising_evolution
areg |> ising_evolution
@test fidelity(majorana2arrayreg(mreg), areg) 1.
end

@testset "expect" begin
nq = 4
circuit = chain(nq)
Expand All @@ -194,12 +223,14 @@ end
θ = π/5
xxg = kron(nq, 2 => X, 3 => Z, 4 => Y)
rg = rot(xxg, θ)
rz = put(nq, 3 => Rz(θ))
push!(circuit, rg)
push!(circuit, put(nq, 3=>Rz(0.5)))
push!(circuit, put(nq, (2,3) => FSWAP))
push!(circuit, put(nq, 1=>Z))
push!(circuit, put(nq, 4=>X))
push!(circuit, rg)
push!(circuit, rz)

ham = put(nq, 1=>Z) + 2kron(nq, 1=>X, 2=>Z, 3=>Z, 4=>X) + 3.5put(nq, 2=>Z)
mreg = FLOYao.zero_state(nq)
Expand All @@ -214,6 +245,12 @@ end
meval = expect(ham[end], mreg)
aeval = expect(ham[end], areg)
@test meval aeval

# test kronblocks inside put blocks
ham = put(nq, 2:3 => kron(2, 1 => X, 2 => Y)) + 2put(nq, 1:2 => kron(2, 1 => X, 2 => Y))
meval = expect(ham, mreg)
aeval = expect(ham, areg)
@test meval aeval
end

@testset "autodiff" begin
Expand All @@ -236,6 +273,12 @@ end
push!(circuit, put(nq, 3=>Rz(0.5)))
push!(circuit, put(nq, 1=>Z))

J = 1.5
h = -1.
hamiltonian = ising_hamiltonian(nq, J, h)
ising_evolution = time_evolve(hamiltonian, 1.)
push!(circuit, ising_evolution)

ham = put(nq, 1=>Z) + 2kron(nq, 1=>X, 2=>Z, 3=>Z, 4=>X) + 3.5put(nq, 2=>Z)
mreg = FLOYao.zero_state(nq)
areg = zero_state(nq)
Expand All @@ -259,7 +302,6 @@ end
@test params_mregδ params_aregδ

@test fidelity(majorana2arrayreg(in_mreg), in_areg) 1.

end

@testset "fidelity" begin
Expand Down

0 comments on commit 35754dc

Please sign in to comment.