Skip to content

Commit

Permalink
export unsafe_apply as the overload interface (#380)
Browse files Browse the repository at this point in the history
* add quick start questions

* add more sections

* fix typo

* add more contents

* change to unsafe_apply

* change to unsafe_apply
  • Loading branch information
Roger-luo authored May 4, 2022
1 parent 865ce53 commit fc3046e
Show file tree
Hide file tree
Showing 20 changed files with 150 additions and 37 deletions.
3 changes: 3 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[deps]
BitBasis = "50ba71b6-fa0f-514d-ae9a-0916efc90dcf"
Compose = "a81c6b42-2e10-5240-aca2-a61377ecd94b"
DocThemeIndigo = "8bac0ac5-51bf-41f9-885e-2bf1ac2bec5f"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
Expand All @@ -14,4 +15,6 @@ Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c"
YaoAPI = "0843a435-28de-4971-9e8b-a9641b2983a8"
YaoArrayRegister = "e600142f-9330-5003-8abb-0ebd767abc51"
YaoBlocks = "418bc28f-b43b-5e0b-a6e7-61bbc1a2c1df"
YaoPlots = "32cfe2d9-419e-45f2-8191-2267705d8dbc"
YaoSym = "3b27209a-d3d6-11e9-3c0f-41eb92b2cb9d"
ZXCalculus = "3525faa3-032d-4235-a8d4-8c2939a218dd"
2 changes: 1 addition & 1 deletion docs/src/examples/4.shor-algorithm/main.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ function bint2_reader(T, k::Int)
return b -> (b&mask, b>>k)
end

function _apply!(reg::ArrayReg, m::KMod)
function Yao.unsafe_apply!(reg::ArrayReg, m::KMod)
nstate = zero(reg.state)

reader = bint2_reader(Int, m.k)
Expand Down
95 changes: 94 additions & 1 deletion docs/src/quick-start.md
Original file line number Diff line number Diff line change
@@ -1 +1,94 @@
# Quick Start
# Quick Start

In this quick start, we list several common use cases for Yao before you
go deeper into the manual.

## Create a quantum register/state

A register is an object that describes a device with an internal state. See [Registers](@ref registers)
for more details. Yao use registers to represent quantum states. The most common register
is the [`ArrayReg`](@ref), you can create it by feeding a state vector to it, e.g

```@repl quick-start
using Yao
ArrayReg(rand(ComplexF64, 2^3))
zero_state(5)
rand_state(5)
product_state(bit"10100")
ghz_state(5)
```

the internal quantum state can be accessed via [`statevec`](@ref) method

```@repl quick-start
statevec(ghz_state(2))
```

for more functionalities about registers please refer to the manual of [`registers`](@ref).

## Create quantum circuit with Yao blocks

Yao uses the quantum "block"s to describe quantum circuits, e.g
the following code creates a 2-qubit circuit

```@repl quick-start
chain(2, put(1=>H), put(2=>X))
```

where `H` gate is at 1st qubit, `X` gate is at 2nd qubit.
A more advanced example is the quantum Fourier transform circuit

```@repl quick-start
A(i, j) = control(i, j=>shift(2π/(1<<(i-j+1))))
B(n, k) = chain(n, j==k ? put(k=>H) : A(j, k) for j in k:n)
qft(n) = chain(B(n, k) for k in 1:n)
qft(3)
```

## Create Hamiltonian with Yao blocks

the quantum "block"s are expressions on quantum operators, thus, it can
also be used to represent a Hamiltonian, e.g we can create a simple Ising
Hamiltonian on 1D chain as following

```@repl quick-start
sum(kron(5, i=>Z, mod1(i+1, 5)=>Z) for i in 1:5)
```

## Automatic differentiate a Yao block

Yao has its own automatic differentiation rule implemented, this allows one obtain
gradients of a loss function by simply putting a `'` mark behind [`expect`](@ref)
or [`fidelity`](@ref), e.g

```@repl quick-start
expect'(X, zero_state(1)=>Rx(0.2))
```

or for fiedlity

```@repl quick-start
fidelity'(zero_state(1)=>Rx(0.1), zero_state(1)=>Rx(0.2))
```

## Combine Yao with ChainRules/Zygote


## Symbolic calculation with Yao block
Yao supports symbolic calculation of quantum circuit via `SymEngine`. We can show


## Plot quantum circuits

The [YaoPlots]() in Yao's ecosystem provides plotting for quantum circuits and ZX diagrams.

```@example quick-start
using Yao.EasyBuild, YaoPlots
using Compose
# show a qft circuit
Compose.SVG(plot(qft_circuit(5)))
```

## Convert quantum circuits to tensor network
## Simplify quantum circuit with ZX calculus
18 changes: 18 additions & 0 deletions lib/YaoAPI/src/blocks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ julia> chcontent(2.0 * X, Y)
Apply a block (of quantum circuit) to a quantum register.
!!! note
to overload `apply!` for a new block, please overload the
[`unsafe_apply!`](@ref) function with same interface. Then
the `apply!` interface will do the size checks on inputs
automatically.
### Examples
```jldoctest; setup=:(using Yao)
julia> r = zero_state(2)
ArrayReg{2, ComplexF64, Array...}
Expand Down Expand Up @@ -210,6 +219,15 @@ julia> measure(r;nshots=10)
"""
@interface apply!

"""
unsafe_apply!(r, block)
Similar to [`apply!`](@ref), but will not check the size of the
register and block, this is mainly used for overloading new blocks,
use at your own risk.
"""
@interface unsafe_apply!

"""
occupied_locs(x)
Expand Down
6 changes: 3 additions & 3 deletions lib/YaoBlocks/src/abstract_block.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ end

YaoAPI.iscommute(op1, op2) = op1 * op2 op2 * op1

function apply!(r::AbstractRegister, b::AbstractBlock)
function YaoAPI.apply!(r::AbstractRegister, b::AbstractBlock)
_check_size(r, b)
_apply!(r, b)
unsafe_apply!(r, b)
end

function _apply!(r::AbstractRegister, b::AbstractBlock)
function YaoAPI.unsafe_apply!(r::AbstractRegister, b::AbstractBlock)
_apply_fallback!(r, b)
end

Expand Down
4 changes: 2 additions & 2 deletions lib/YaoBlocks/src/composite/chain.jl
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ function mat(::Type{T}, c::ChainBlock{D}) where {T,D}
end
end

function _apply!(r::AbstractRegister, c::ChainBlock)
function YaoAPI.unsafe_apply!(r::AbstractRegister, c::ChainBlock)
for each in c.blocks
_apply!(r, each)
YaoAPI.unsafe_apply!(r, each)
end
return r
end
Expand Down
4 changes: 2 additions & 2 deletions lib/YaoBlocks/src/composite/control.jl
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ cz(ctrl_locs, loc::Int) = @λ(n -> cz(n, ctrl_locs, loc))
mat(::Type{T}, c::ControlBlock{BT,C}) where {T,BT,C} =
cunmat(c.n, c.ctrl_locs, c.ctrl_config, mat(T, c.content), c.locs)

function _apply!(r::AbstractRegister, c::ControlBlock)
function YaoAPI.unsafe_apply!(r::AbstractRegister, c::ControlBlock)
instruct!(r, mat_matchreg(r, c.content), c.locs, c.ctrl_locs, c.ctrl_config)
return r
end
Expand All @@ -143,7 +143,7 @@ end
for G in [:X, :Y, :Z, :S, :T, :Sdag, :Tdag]
GT = Expr(:(.), :ConstGate, QuoteNode(Symbol(G, :Gate)))

@eval function _apply!(r::AbstractRegister, c::ControlBlock{<:$GT})
@eval function YaoAPI.unsafe_apply!(r::AbstractRegister, c::ControlBlock{<:$GT})
instruct!(r, Val($(QuoteNode(G))), c.locs, c.ctrl_locs, c.ctrl_config)
return r
end
Expand Down
2 changes: 1 addition & 1 deletion lib/YaoBlocks/src/composite/kron.jl
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ function mat(::Type{T}, k::KronBlock{D,M}) where {T,D,M}
end
end

function _apply!(r::AbstractRegister, k::KronBlock)
function YaoAPI.unsafe_apply!(r::AbstractRegister, k::KronBlock)
for (locs, block) in zip(k.locs, k.blocks)
_instruct!(r, block, Tuple(locs))
end
Expand Down
8 changes: 4 additions & 4 deletions lib/YaoBlocks/src/composite/put_block.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ cache_key(pb::PutBlock) = cache_key(pb.content)
mat(::Type{T}, pb::PutBlock{2,1}) where {T} = u1mat(pb.n, mat(T, pb.content), pb.locs...)
mat(::Type{T}, pb::PutBlock{2,C}) where {T,C} = unmat(pb.n, mat(T, pb.content), pb.locs)

function _apply!(r::AbstractRegister, pb::PutBlock{D}) where D
function YaoAPI.unsafe_apply!(r::AbstractRegister, pb::PutBlock{D}) where D
instruct!(r, mat_matchreg(r, pb.content), pb.locs)
return r
end
Expand All @@ -88,7 +88,7 @@ end
# specialization
for G in [:X, :Y, :Z, :T, :S, :Sdag, :Tdag, :H]
GT = Expr(:(.), :ConstGate, QuoteNode(Symbol(G, :Gate)))
@eval function _apply!(r::AbstractRegister, pb::PutBlock{2,C,<:$GT}) where {C}
@eval function YaoAPI.unsafe_apply!(r::AbstractRegister, pb::PutBlock{2,C,<:$GT}) where {C}
instruct!(r, Val($(QuoteNode(G))), pb.locs)
return r
end
Expand Down Expand Up @@ -152,7 +152,7 @@ function mat(::Type{T}, g::Swap) where {T}
return PermMatrix(orders, ones(T, nlevel(g)^g.n))
end

_apply!(r::AbstractRegister, g::Swap) = (instruct!(r, Val(:SWAP), g.locs); r)
YaoAPI.unsafe_apply!(r::AbstractRegister, g::Swap) = (instruct!(r, Val(:SWAP), g.locs); r)
occupied_locs(g::Swap) = g.locs

"""
Expand All @@ -179,7 +179,7 @@ for (G, GT) in [
(:Rz, :(PutBlock{2,1,RotationGate{2, T,ZGate}} where {T})),
(:PSWAP, :(PSwap)),
]
@eval function _apply!(reg::AbstractRegister, g::$GT)
@eval function YaoAPI.unsafe_apply!(reg::AbstractRegister, g::$GT)
instruct!(reg, Val($(QuoteNode(G))), g.locs, g.content.theta)
return reg
end
Expand Down
8 changes: 4 additions & 4 deletions lib/YaoBlocks/src/composite/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ end

chsubblocks(x::Add, it) = Add(it)

function _apply!(r::AbstractRegister, x::Add)
function YaoAPI.unsafe_apply!(r::AbstractRegister, x::Add)
isempty(x.list) && return r
length(x.list) == 1 && return _apply!(r, x.list[])
length(x.list) == 1 && return YaoAPI.unsafe_apply!(r, x.list[])

res = mapreduce(blk -> _apply!(copy(r), blk), regadd!, x.list[1:end-1])
_apply!(r, x.list[end])
res = mapreduce(blk -> YaoAPI.unsafe_apply!(copy(r), blk), regadd!, x.list[1:end-1])
YaoAPI.unsafe_apply!(r, x.list[end])
regadd!(r, res)
r
end
Expand Down
6 changes: 3 additions & 3 deletions lib/YaoBlocks/src/composite/repeated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ mat(::Type{T}, rb::RepeatedBlock{D}) where {T,D} =
YaoArrayRegister.hilbertkron(rb.n, fill(mat(T, rb.content), length(rb.locs)), [rb.locs...]; nlevel=D)
mat(::Type{T}, rb::RepeatedBlock{D,0,GT}) where {T,D,GT} = IMatrix{D^nqudits(rb),T}()

function _apply!(r::AbstractRegister, rp::RepeatedBlock)
function YaoAPI.unsafe_apply!(r::AbstractRegister, rp::RepeatedBlock)
m = mat_matchreg(r, rp.content)
for addr in rp.locs
instruct!(r, m, Tuple(addr:addr+nqudits(rp.content)-1))
Expand All @@ -129,13 +129,13 @@ end
# specialization
for G in [:X, :Y, :Z, :S, :T, :Sdag, :Tdag]
GT = Expr(:(.), :ConstGate, QuoteNode(Symbol(G, :Gate)))
@eval function _apply!(r::AbstractRegister, rp::RepeatedBlock{N,C,$GT}) where {N,C}
@eval function YaoAPI.unsafe_apply!(r::AbstractRegister, rp::RepeatedBlock{N,C,$GT}) where {N,C}
instruct!(r, Val($(QuoteNode(G))), rp.locs)
return r
end
end

_apply!(reg::AbstractRegister, rp::RepeatedBlock{D,0}) where D = reg
YaoAPI.unsafe_apply!(reg::AbstractRegister, rp::RepeatedBlock{D,0}) where D = reg

cache_key(rb::RepeatedBlock) = (rb.locs, cache_key(rb.content))

Expand Down
4 changes: 2 additions & 2 deletions lib/YaoBlocks/src/composite/subroutine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ occupied_locs(c::Subroutine) = map(i -> c.locs[i], c.content |> occupied_locs)
chsubblocks(pb::Subroutine{D}, blk::AbstractBlock{D}) where {D} = Subroutine(pb.n, blk, pb.locs)
PropertyTrait(::Subroutine) = PreserveAll()

function _apply!(r::AbstractRegister, c::Subroutine)
function YaoAPI.unsafe_apply!(r::AbstractRegister, c::Subroutine)
focus!(r, c.locs)
_apply!(r, c.content)
YaoAPI.unsafe_apply!(r, c.content)
relax!(r, c.locs, to_nactive = nqudits(c))
return r
end
Expand Down
8 changes: 4 additions & 4 deletions lib/YaoBlocks/src/composite/tag/cache.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,17 @@ function CacheServers.pull(c::CachedBlock)
return pull(c.server, c.content)
end

function _apply!(r::AbstractArrayReg{D,T}, c::CachedBlock, signal) where {D,T}
function YaoAPI.unsafe_apply!(r::AbstractArrayReg{D,T}, c::CachedBlock, signal) where {D,T}
if signal > c.level
r.state .= mat(T, c) * r
else
_apply!(r, c.content)
YaoAPI.unsafe_apply!(r, c.content)
end
return r
end

_apply!(r::AbstractRegister, c::CachedBlock) = _apply!(r, c.content)
_apply!(r::AbstractArrayReg{D,T}, c::CachedBlock) where {D,T} = (r.state .= mat(T, c) * r.state; r)
YaoAPI.unsafe_apply!(r::AbstractRegister, c::CachedBlock) = YaoAPI.unsafe_apply!(r, c.content)
YaoAPI.unsafe_apply!(r::AbstractArrayReg{D,T}, c::CachedBlock) where {D,T} = (r.state .= mat(T, c) * r.state; r)

Base.similar(c::CachedBlock, level::Int) = CachedBlock(c.server, c.content, level)
Base.copy(c::CachedBlock) = CachedBlock(c.server, copy(c.content), c.level)
Expand Down
4 changes: 2 additions & 2 deletions lib/YaoBlocks/src/composite/tag/scale.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ cache_key(x::Scale) = (factor(x), cache_key(content(x)))
mat(::Type{T}, x::Scale) where {T} = T(x.alpha) * mat(T, content(x))
mat(::Type{T}, x::Scale{Val{S}}) where {T,S} = T(S) * mat(T, content(x))

function _apply!(r::AbstractArrayReg, x::Scale{S}) where {S}
_apply!(r, content(x))
function YaoAPI.unsafe_apply!(r::AbstractArrayReg, x::Scale{S}) where {S}
YaoAPI.unsafe_apply!(r, content(x))
regscale!(r, factor(x))
return r
end
4 changes: 2 additions & 2 deletions lib/YaoBlocks/src/composite/unitary_channel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ UnitaryChannel(it, weights) = UnitaryChannel(collect(it), weights)
UnitaryChannel(it) = UnitaryChannel(collect(it))
nqudits(uc::UnitaryChannel) = uc.n

function _apply!(r::AbstractRegister, x::UnitaryChannel)
_apply!(r, sample(x.operators, x.weights))
function YaoAPI.unsafe_apply!(r::AbstractRegister, x::UnitaryChannel)
YaoAPI.unsafe_apply!(r, sample(x.operators, x.weights))
end

function mat(::Type{T}, x::UnitaryChannel) where {T}
Expand Down
2 changes: 1 addition & 1 deletion lib/YaoBlocks/src/primitive/measure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ Measure(;
)
mat(x::Measure) = error("use BlockMap to get its matrix.")

function _apply!(r::AbstractRegister{D}, m::Measure{D}) where {D}
function YaoAPI.unsafe_apply!(r::AbstractRegister{D}, m::Measure{D}) where {D}
m.results = measure!(m.postprocess, m.operator, r, m.locations; rng = m.rng)
return r
end
Expand Down
4 changes: 2 additions & 2 deletions lib/YaoBlocks/src/primitive/rotation_gate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ mat(::Type{T}, R::RotationGate{1,<:Any,<:YGate}) where {T} =
# mat(R::RotationGate{1, T, ZGate{Complex{T}}}) where T =
# SMatrix{2, 2, Complex{T}}(cos(R.theta/2)-im*sin(R.theta/2), 0, 0, cos(R.theta/2)+im*sin(R.theta/2))

function _apply!(r::ArrayReg, rb::RotationGate)
function YaoAPI.unsafe_apply!(r::ArrayReg, rb::RotationGate)
v0 = copy(r.state)
_apply!(r, rb.block)
unsafe_apply!(r, rb.block)
# NOTE: we should not change register's memory address,
# or batch operations may fail
r.state .= -im * sin(rb.theta / 2) * r.state + cos(rb.theta / 2) * v0
Expand Down
2 changes: 1 addition & 1 deletion lib/YaoBlocks/src/primitive/time_evolution.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function LinearAlgebra.mul!(y::AbstractVector, A::BlockMap{T,GT}, x::AbstractVec
return y
end

function _apply!(reg::AbstractArrayReg{D,T}, te::TimeEvolution) where {D,T}
function YaoAPI.unsafe_apply!(reg::AbstractArrayReg{D,T}, te::TimeEvolution) where {D,T}
if isdiagonal(te.H)
reg.state .*= exp.((-im * te.dt) .* diag(mat(T, te.H)))
return reg
Expand Down
2 changes: 1 addition & 1 deletion lib/YaoBlocks/test/composite/cache.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ end
@test pull(g) mat(X)

clear!(g)
@test state(YaoBlocks._apply!(arrayreg(bit"1"), g, 2)) state(arrayreg(bit"0"))
@test state(unsafe_apply!(arrayreg(bit"1"), g, 2)) state(arrayreg(bit"0"))
@test_throws KeyError pull(g)
end

Expand Down
1 change: 0 additions & 1 deletion src/EasyBuild/block_extension/blocks.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
import .YaoBlocks: _apply!
include("shortcuts.jl")
include("FSimGate.jl")

0 comments on commit fc3046e

Please sign in to comment.