Skip to content
This repository has been archived by the owner on Apr 30, 2022. It is now read-only.

rename & add doc #18

Merged
merged 12 commits into from
Dec 12, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Extensions for Yao.
* variational_circuit(n): construct a random parametrized circuit.
* heisenberg(n): construct a heisenberg hamiltonian.
* rand_supremacy2d(nx, ny, depth): construct a quantum supremacy circuit.
* QFTCircuit(n): construct a quantum fourier transformation circuit.
* `QFT`(n): construct a quantum fourier transformation circuit.

#### Block extensions
* Diff: differentiable node. See [example/port_zygote](example/port_zygote.jl) as a using example.
Expand Down
54 changes: 42 additions & 12 deletions src/block_extension/QFTBlock.jl
Original file line number Diff line number Diff line change
@@ -1,20 +1,50 @@
export QFTBlock
export QFT
using YaoBlocks
using YaoBase
using BitBasis
using YaoArrayRegister
using LinearAlgebra
using FFTW

struct QFTBlock{N} <: PrimitiveBlock{N} end
mat(::Type{T}, q::QFTBlock{N}) where {T, N} = T.(applymatrix(q))
"""
QFT{N} <: PrimitiveBlock{N}

apply!(reg::ArrayReg{B}, ::QFTBlock) where B = (reg.state = ifft!(invorder_firstdim(reg |> state), 1)*sqrt(1<<nactive(reg)); reg)
apply!(reg::ArrayReg{B}, ::Daggered{N, <:QFTBlock}) where {B,N} = (reg.state = invorder_firstdim(fft!(reg|>state, 1)/sqrt(1<<nactive(reg))); reg)
Quantum Fourier Transform node. See also [`qft_circuit`](@ref).
"""
struct QFT{N} <: PrimitiveBlock{N} end

"""
qft(n)

Create a Quantum Fourier Transform block. See also [`qft_circuit`](@ref).
"""
qft(n) = QFT{n}()

mat(::Type{T}, q::QFT{N}) where {T, N} = T.(applymatrix(q))

function apply!(r::ArrayReg{B}, ::QFT) where B
α = sqrt(1 << nactive(r))
invorder!(r)
lmul!(α, ifft!(statevec(r)))
return r
end

function apply!(r::ArrayReg{B}, ::Daggered{N, <:QFT}) where {B,N}
α = sqrt(1 << nactive(r))
invorder!(r)
lmul!(α, fft!(statevec(r)))
return r
end

# traits
ishermitian(q::QFTBlock{N}) where N = N==1
isreflexive(q::QFTBlock{N}) where N = N==1
isunitary(q::QFTBlock{N}) where N = true
ishermitian(q::QFT{N}) where N = N==1
isreflexive(q::QFT{N}) where N = N==1
isunitary(q::QFT{N}) where N = true

function print_block(io::IO, pb::QFTBlock{N}) where N
printstyled(io, "QFT(1-$N)"; bold=true, color=:blue)
function print_block(io::IO, pb::QFT{N}) where N
printstyled(io, "qft(1-$N)"; bold=true, color=:blue)
end

function print_block(io::IO, pb::Daggered{N,<:QFTBlock}) where {N, T}
printstyled(io, "IQFT(1-$N)"; bold=true, color=:blue)
function print_block(io::IO, pb::Daggered{N,<:QFT}) where {N, T}
printstyled(io, "iqft(1-$N)"; bold=true, color=:blue)
end
36 changes: 31 additions & 5 deletions src/easybuild/QFTCircuit.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
using FFTW
export QFTCircuit
export qft_circuit

CRk(i::Int, j::Int, k::Int) = control([i, ], j=>shift(2π/(1<<k)))
CRot(n::Int, i::Int) = chain(n, i==j ? put(i=>H) : CRk(j, i, j-i+1) for j = i:n)
QFTCircuit(n::Int) = chain(n, CRot(n, i) for i = 1:n)
"""
cphase(i, j, k)

Control phase gate.
"""
cphase(i::Int, j::Int, k::Int) = control(i, j=>shift(2π/(1<<k)))
hcphases(n::Int, i::Int) = chain(n, i==j ? put(i=>H) : cphase(j, i, j-i+1) for j = i:n)

"""
qft_circuit(n)

Create a Quantum Fourer Transform circuit. See also [`QFT`](@ref).
"""
qft_circuit(n::Int) = chain(n, hcphases(n, i) for i = 1:n)

qft(l, n) = l == n ? H : chain(
chain(n, l==j ? put(l=>H) : cphase(j, l, j-l+1) for j = l:n),
qft(l-1, n)
)

function qft(l, n)
if l == n
return put(n, l=>H)
else
return chain(
chain(n, l==j ? put(l=>H) : cphase(j, l, j-l+1) for j = l:n),
qft(l+1, n)
)
end
end
4 changes: 2 additions & 2 deletions src/easybuild/openbox.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export openbox

For a black box, like QFTBlock, you can get its white box (faithful simulation) using this function.
"""
openbox(q::QFTBlock{N}) where N = QFTCircuit(N)
openbox(q::Daggered{<:QFTBlock, N}) where {N} = QFTCircuit(N)'
openbox(q::QFT{N}) where N = qft_circuit(N)
openbox(q::Daggered{<:QFT, N}) where {N} = qft_circuit(N)'

function openbox(fs::FSimGate)
if fs.theta ≈ π/2
Expand Down
18 changes: 9 additions & 9 deletions test/block_extension/QFTBlock.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ using FFTW

@testset "QFT" begin
num_bit = 5
fftblock = QFTCircuit(num_bit)
fftblock = qft_circuit(num_bit)
ifftblock = fftblock'
reg = rand_state(num_bit)
rv = copy(statevec(reg))

@test Matrix(mat(chain(3, QFTCircuit(3) |> adjoint, QFTCircuit(3)))) ≈ IMatrix(1<<3)
@test Matrix(mat(chain(3, qft_circuit(3) |> adjoint, qft_circuit(3)))) ≈ IMatrix(1<<3)

# test ifft
reg1 = apply!(copy(reg), ifftblock)
Expand All @@ -28,24 +28,24 @@ using FFTW
end


@testset "QFTBlock" begin
@testset "QFT" begin
num_bit = 5
qft = QFTCircuit(num_bit)
qft = qft_circuit(num_bit)
iqft = adjoint(qft)
qftblock = QFTBlock{num_bit}()
iqftblock = QFTBlock{num_bit}() |> adjoint
qftblock = QFT{num_bit}()
iqftblock = QFT{num_bit}() |> adjoint
@test openbox(qftblock) == qft
@test openbox(iqftblock) == iqft
reg = rand_state(num_bit)

@test Matrix(mat(chain(3, QFTBlock{3}() |> adjoint, QFTBlock{3}()))) ≈ IMatrix(1<<3)
@test Matrix(mat(chain(3, QFT{3}() |> adjoint, QFT{3}()))) ≈ IMatrix(1<<3)

# permute lines (Manually)
@test apply!(copy(reg), iqft) ≈ apply!(copy(reg), QFTBlock{num_bit}() |> adjoint)
@test apply!(copy(reg), iqft) ≈ apply!(copy(reg), QFT{num_bit}() |> adjoint)

# test fft
@test apply!(copy(reg), qft) ≈ apply!(copy(reg), qftblock)

# regression test for nactive
@test apply!(focus!(copy(reg), 1:3), QFTBlock{3}()) |> isnormalized
@test apply!(focus!(copy(reg), 1:3), QFT{3}()) |> isnormalized
end