This package has been moved into the Yao repo
Standard basic quantum circuit simulator building blocks.
This is a component package for Yao.jl. It contains the abstract definitions and basic implementation of Yao's circuit building blocks.
Standard basic quantum circuit simulator building blocks. (archived, for it is moved to Yao.jl)
License: Apache License 2.0
This package has been moved into the Yao repo
Standard basic quantum circuit simulator building blocks.
This is a component package for Yao.jl. It contains the abstract definitions and basic implementation of Yao's circuit building blocks.
julia> dispatch!(chain(Rx(0.1), Rx(0.2)), [0.3, 0])
ERROR: AssertionError: expect 1 parameters, got 2
Stacktrace:
[1] dispatch!(::RotationGate{1,Float64,XGate{Complex{Float64}}}, ::Base.Iterators.Drop{Array{Float64,1}}) at /home/leo/.julia/dev/YaoBlocks/src/abstract_block.jl:224
[2] dispatch!(::ChainBlock{1,Complex{Float64},AbstractBlock{1,Complex{Float64}}}, ::Array{Float64,1}) at /home/leo/.julia/dev/YaoBlocks/src/abstract_block.jl:228
[3] top-level scope at none:0
as proposed by @emerali we could optimize this pattern by using Wlash-Hadamard transform
YaoBlocks.jl/src/composite/repeated.jl
Line 102 in 636656a
MWE:
chain(4, n->kron(n, 1=>H))
causing error:
CRk(i::Int, j::Int, k::Int) = control([i, ], j=>shift(2π/(1<<k)))
CRot(n::Int, i::Int) = chain(i==j ? kron(i=>H) : CRk(j, i, j-i+1) for j = i:n)
QFTCircuit(n::Int) = chain(n, CRot(n, i) for i = 1:n)
@JuliaRegistrator register()
Hi there. I am going to implement a quantum circuit using Yao.jl
, which contains two blocks sharing same parameters. Let's say U=u(a)s(b)v(a)
and a
b
are variational parameters in this circuit.
Specifically I can implement this circuit manually and compute their gradients using some custom methods, which is also my current method. However, if the structures of u(a)
and v(a)
are more complex, manual implementation becomes somehow tedious and boring.
I noticed that the same block instance has sharing parameters, but potentially I have different blocks in u(a)
and v(a)
(a specific circumstance is u=dagger(v)
which is like VFF in arXiv:1910.04292 ).
I also tried Daggered
method, but it looks like it returns a new block with no sharing parameters.
I also thought a custom block, but in order to obtain the AD function, I have to implement mat_back!
method, which is as complex as manual implementation.
So, is it possible to do this thing directly in Yao.jl
and also obtain the AD function?
thanks your time!
I am trying to get quantum backpropagation with GPU acceleration working for MyCustomBlock <: YaoBlocks.PrimitiveBlock{2}
. It has only one real parameter (like e.g. a rotation gate) and in my circuits always occurs inside a PuttBlock
. Hence the easiest solution seemed to be to write my own
mat_back!(::Type{T}, rb::PutBlock{N,C,MyCustomBlock}, adjy, collector)
to replace the version in YaoBlocks/autodiff/mat_back.jl:43
. But I don't exactly understand
what adjcunmat
in line 45 does and what I should do instead
MWE:
function instruct2!(state, U, loc)
a, c, b, d = U
step = 1 << (loc - 1)
step_2 = 1 << loc
for j in 0:step_2:size(state, 1)-step
@inbounds for i in j+1:j+step
YaoArrayRegister.u1rows!(state, i, i+step, a, b, c, d)
end
end
return state
end
The performance of instruct is quite different on my machine with Julia 1.1 with SMatrix
and Matrix
, unexpectedly, SMatrix
is even slower. This is causing current QCBM circuit slower than before.
MWE:
g = kron(2, 1=>(im * Z))
got
julia> t
nqubits: 2, datatype: Complex{Float64}
kron
└─ 1=>Z gate
should be
julia> t
nqubits: 2, datatype: Complex{Float64}
kron
└─ 1=> [+im] Z gate
This issue is used to trigger TagBot; feel free to unsubscribe.
If you haven't already, you should update your TagBot.yml
to include issue comment triggers.
Please see this post on Discourse for instructions and more details.
usedbits
-> occupied_locations
: directly follows the documentation:occupied locations of a given block.
I tried to make this shorter, but it has to follow the convention locations
, or occupied_locs
. used
is not accurate, it sounds like this location was used before, but still available which is in contrast to what this should mean.
block
/parent
-> content
: name conflict in local scope, use content instead. This method is for all blocks with a block inside, no matter it is a primitive or composite.
chblock
-> chsubblocks(blk, subblk)
: make use of multiple dispatch, when the 2nd arg is a block, just treat it as chblock, since this make sense for all composite blocks ( when chain
, kron
, etc. have a single content block and containers only have one content block)
addrs
is removed, it's never used.
move constant gates to module ConstGate
(not done yet, need to discuss what kind of common gates still need to be exported out of YaoBlockTree
, e.g X
, Y
, Z
)
matrixgate
-> matgate
: shorter name for convenience
measure
is used to construct Measure
block (no conflict with YaoBase
, but is a type pirate, which is fine)
AddBlock
-> Sum
to make use of Prod
's code, they are both binary operators, shares a lot common functionalities.
ctrl_qubits
etc. -> ctrl_locs
, ctrl_val
/val
etc. -> ctrl_config
updating...
expv_timestep
converge faster in Lancoz because it divide the total time step into small steps and re-use the Krylov space, as suggested by @ChrisRackauckas we should try this for our time evolution.
And we need to investigate the in-place exp SciML/ExponentialUtilities.jl#20 in upstream.
MWE:
r = ArrayReg(view(rand(ComplexF64, 16, 2), :, 1))
g = put(4, 1=>X) + put(4, 2=>X)
r |> g
This cause the Lancoz process in time evolution block fails.
Current, for simplicity in implementation, I just make use of the Prod
's simplification rules for chain
, but this will cause chain
become a prod
after simplification.
This is not a big deal, since:
prod
uses the order of production and is static, and chain follows the order of application with a dynamic list).simplify
itself will and has to change the type, so I think it is generally fine.But it might have some inconvenience in some cases, since prod
is immutable while chain
is mutable. I'll leave this issue here, to see if there's any use cases on this in the future then we shall consider change this behaviour.
we are missing a lot docs for constant gates, need to add them later when one has some more time
if you try to run the test, we get this now, seems to be
Warning: `a::StaticArray + b::Number` is deprecated, use `a .+ b` instead.
│ caller = (::getfield(YaoBlocks, Symbol("##16#17")){StaticArrays.SArray{Tuple{2,2},Basic,2,4},StaticArrays.SArray{Tuple{2},Int64,1,2},SparseArrays.SparseMatrixCSC{Basic,Int64}})(::Int64) at routines.jl:201
└ @ YaoBlocks ~/.julia/packages/YaoBlocks/RfMRn/src/routines.jl:201
mat
returns ComplexF64
, by default. For GeneralMatrixBlock
, it should return the element type of the matrix.
julia> M = rand(Float32,2,2)
2×2 Array{Float32,2}:
0.0412188 0.879695
0.251251 0.767503
julia> MB = matblock(M)
matblock(...)
julia> typeof(MB)
GeneralMatrixBlock{1,1,Complex{Float32},Array{Complex{Float32},2}}
julia> mat(MB)
┌ Warning: converting Float32 to eltype Complex{Float64}, consider create another matblock with eltype Complex{Float64}
└ @ YaoBlocks ~/.julia/packages/YaoBlocks/Q5IBc/src/primitive/general_matrix_gate.jl:52
2×2 Array{Complex{Float64},2}:
0.0412188+0.0im 0.879695+0.0im
0.251251+0.0im 0.767503+0.0im
Currently the traits e.g PreserveAll
is implemented manually, we should make use of SimpleTraits to make this more elegant and powerful.
e.g with trait IsHermitian
, we could dispatch time evolution's expv
based on this trait, and the circuit simplification should be easier to make use of multiple dispatch.
put
rather than repeat
?rand
in this benchmark, please specify a deterministic position for benchmark.@Roger-luo
I tried to construct a hamiltonian, but got the following printing information in error message. I worried about the performance of having the following long type parameters. It is possible?
I wonder why static type parameter would be useful in optimization.
It is pretty heavy in printing.
solving hamiltonian: Error During Test at /home/leo/.julia/dev/QuAlgorithmZoo/test/hamiltonian_solvers.jl:6
Got exception outside of a @test
MethodError: no method matching TimeEvolution(::CachedBlock{CacheServers.DefaultServer{AbstractBlock,CacheFragment},
Sum{8,Complex{Float64},Tuple{Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64
},XGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},XGate{Complex{Float64}}}}},Prod{
8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},YGate{Complex{Float64}}},PutBlock
{8,1,1,Complex{Float64},YGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8
,1,1,Complex{Float64},ZGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},ZGate{Comp
lex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},XGate{Comple
x{Float64}}},PutBlock{8,1,1,Complex{Float64},XGate{Complex{Float64}}}}},Prod{8,Complex{Float
64},Tuple{PutBlock{8,1,1,Complex{Float64},YGate{Complex{Float64}}},PutBlock{8,1,1,Complex{
Float64},YGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Fl
oat64},ZGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},ZGate{Complex{Float64}}}}},
Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},XGate{Complex{Float64}}},Put
Block{8,1,1,Complex{Float64},XGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBl
ock{8,1,1,Complex{Float64},YGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},YGate{
Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},ZGate{C
omplex{Float64}}},PutBlock{8,1,1,Complex{Float64},ZGate{Complex{Float64}}}}},Prod{8,Comple
x{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},XGate{Complex{Float64}}},PutBlock{8,1,1,Co
mplex{Float64},XGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Com
plex{Float64},YGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},YGate{Complex{Float
64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},ZGate{Complex{Float6
4}}},PutBlock{8,1,1,Complex{Float64},ZGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tupl
e{PutBlock{8,1,1,Complex{Float64},XGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},
XGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},Y
Gate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},YGate{Complex{Float64}}}}},Prod{8,
Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},ZGate{Complex{Float64}}},PutBlock{8
,1,1,Complex{Float64},ZGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1
,1,Complex{Float64},XGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},XGate{Comple
x{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},YGate{Complex{
Float64}}},PutBlock{8,1,1,Complex{Float64},YGate{Complex{Float64}}}}},Prod{8,Complex{Float6
4},Tuple{PutBlock{8,1,1,Complex{Float64},ZGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Fl
oat64},ZGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Flo
at64},XGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},XGate{Complex{Float64}}}}},P
rod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},YGate{Complex{Float64}}},PutB
lock{8,1,1,Complex{Float64},YGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlo
ck{8,1,1,Complex{Float64},ZGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},ZGate{C
omplex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Complex{Float64},XGate{Co
mplex{Float64}}},PutBlock{8,1,1,Complex{Float64},XGate{Complex{Float64}}}}},Prod{8,Complex{
Float64},Tuple{PutBlock{8,1,1,Complex{Float64},YGate{Complex{Float64}}},PutBlock{8,1,1,Com
plex{Float64},YGate{Complex{Float64}}}}},Prod{8,Complex{Float64},Tuple{PutBlock{8,1,1,Compl
ex{Float64},ZGate{Complex{Float64}}},PutBlock{8,1,1,Complex{Float64},ZGate{Complex{Float6
4}}}}}}},8,Complex{Float64}}, ::Complex{Int64})
Now is
julia> setiparams!(chain(5), (0.3,))
ERROR: StackOverflowError:
Stacktrace:
[1] setiparams!(::ChainBlock{5,Complex{Float64},AbstractBlock{5,Complex{Float64}}}, ::Float64) at /home/leo/.julia/dev/YaoBlocks/src/abstract_block.jl:132 (repeats 8122 times)
[2] top-level scope at none:0
Should throw a Number of parameter mismatch error.
This line of code
YaoBlocks.jl/src/abstract_block.jl
Line 132 in 3936a66
should be written in a more restrictive way.
julia> kron(2, (1, 2)=>X)
ERROR: location of sparse distributed blocks must be explicit declared with pair (e.g 2=>X)
We need better error msg for types as well instead of suggesting pairs.
Clifford group can be stored by a tableau and be calculated in poly time (on stabilizer states) with either the tableau based algorithm or graph states. A block for Cliffords is more useful when construct/transform/calculate things like graph state, error correction codes.
But since this is deeply related to graph states, this might should go into another package with graph state together.
Related work: Cliffords.jl
FYI: https://arxiv.org/pdf/quant-ph/0602096.pdf
abstract type AbstractBlock{N, T} end
T
is mainly for matrices, which is not useful in most cases, and will causing the following things to work/doesn't work, which completely make no sense since blocks are only representations of quantum operators, and do not have specific dependency on concrete types.
T
)This should be fixed before we become stable (v1.0), and will results in the following un-breaking changes:
T
is removed, and is only needed for mat
and methods use mat
, we could add an extra optional arg to mat
as mat([T=ComplexF64], x)
mat
will try to return the matrix we think the most efficient for the block, but it is quite confusing and not convenient when we need the matrix, it would be nice to have some common matrices type constructor to work on blocks. and define some convert
functions as well.this will break some extension, which subtyping our AbstractBlock
, but should be very easy to fix (by simply deleting all T
s) for downstream
Measure, show locs, collapseto and operator information
Control, controlled qubits
Hi there, I use Yao.jl
for my quantum computation project, where I should define a new gate with some parameters.
After the definition of my gate and its mat
function, I can compute the matrix of mygate
.i.e: mat(ComplexF64, mygate)
works well.
However, I find error MethodError: no method matching mat(::Type{ComplexF64}, ::mygate)
, when I use Matrix(chain(n, mygate))
and operator_fidelity(block, mygate)
. Did I do something incorrect?
I was reading the documentation of Yao and found that in the description of function expect'
, the Note (blue box) says that expect'
is a slight modification of expect
for the cases of batched registers when we input a pair of register and circuit, which I assume implies that expect
can also return gradients.
However, it is also stated that "expect" only returns the expectation value of the observable, which is contradictory to the Note (blue box).
From my test
julia> expect(h, zero_state(4) => c) == expect(h, zero_state(4) |> c)
true
julia> expect'(h, zero_state(4)|>c)
ArrayReg{1, Complex{Float64}, Array...}
active qubits: 4/4
So it seems that expect
just returns the expectation value in either case and expect'
doesn't return expectation value even when we don't input the pair of register and circuit.
Do you intend to differ expect
and expect'
by just the functionality of accumulating the outputs for multiple-batch cases? Or do you want to specify expect'
as the function to get gradients of a differentiable circuit? So far I find the logic and documentation about those two functions are a bit confusing.
Also, I think it would be better if you could specify the requirement of the circuit inside the input pair. Does it have to be the variational_circuit
from YaoExtension.jl
or can it be any parameterized circuit but marked with differentiable blocks?
Thank you very much!
So sometimes it's useful to embed a classical control inside the circuit, it controls a part of the circuit by measuring some qubits out.
The desired behavior can be measure and remove or measure and collapse to some qubits config.
this is not compatible with previous versions.
I hit this while implementing Shor algorithm.
This function conflicts with the factor
function in Primes.jl
, I think we don't need to export it by default for Scale
, in most cases you can just use dot
. instead of factor
, after 1.0, there's no benefit to define an extra method for members anyway (since there are inspect functions like getproperty
etc.)
@JuliaRegistrator register
Thank you @GiggleLiu for #166 . I could run your example successfully with 0.11.7, but I ran into the following issue that I'm trying to solve.
When I run the following slightly modified code
using Yao
using Random
using Zygote
using YaoArrayRegister
using ForwardDiff
using Test
H = chain(5, put(1=>Z))
# H = sum([chain(5, put(k=>Z)) for k=1:5])
c = chain(put(5, 2=>chain(Rx(0.4), Rx(0.5))), cnot(5, 3, 1), put(5, 3=>Rx(-0.5)))
dispatch!(c, :random)
function loss(reg::AbstractRegister, circuit::AbstractBlock{N}) where N
reg = apply(copy(reg), circuit)
st = state(reg)
reg2 = apply(copy(reg), H)
st2 = state(reg2)
sum(real(st.*st2))
end
reg0 = zero_state(5)
params = rand!(parameters(c))
paramsδ = Zygote.gradient(params->loss(reg0, dispatch(c, params)), params)[1]
fparamsδ = ForwardDiff.gradient(params->loss(ArrayReg(Matrix{Complex{eltype(params)}}(reg0.state)), dispatch(c, params)), params)
@test fparamsδ ≈ paramsδ
Tests pass. Note that H is not the 'circuit' like in your example, but another unitary operator.
However, when I switch H to a sum of unitaries (like a Hamiltonian, H = sum([chain(5, put(k=>X)) for k=1:5])
) I get the following error:
ERROR: LoadError: UndefKeywordError: keyword argument in not assigned
Stacktrace:
[1] apply_back!(st::Tuple{ArrayReg{1, ComplexF64, Matrix{ComplexF64}}, ArrayReg{1, ComplexF64, Matrix{ComplexF64}}}, circuit::Add{5}, collector::Vector{Any})
@ YaoBlocks.AD ~/.julia/packages/YaoBlocks/xRlSK/src/autodiff/apply_back.jl:112
[2] apply_back(st::Tuple{ArrayReg{1, ComplexF64, Matrix{ComplexF64}}, ArrayReg{1, ComplexF64, Matrix{ComplexF64}}}, block::Add{5}; kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ YaoBlocks.AD ~/.julia/packages/YaoBlocks/xRlSK/src/autodiff/apply_back.jl:151
[3] apply_back(st::Tuple{ArrayReg{1, ComplexF64, Matrix{ComplexF64}}, ArrayReg{1, ComplexF64, Matrix{ComplexF64}}}, block::Add{5})
@ YaoBlocks.AD ~/.julia/packages/YaoBlocks/xRlSK/src/autodiff/apply_back.jl:150
[4] (::YaoBlocks.AD.var"#21#22"{Add{5}, ArrayReg{1, ComplexF64, Matrix{ComplexF64}}})(outδ::ArrayReg{1, ComplexF64, Matrix{ComplexF64}})
@ YaoBlocks.AD ~/.julia/packages/YaoBlocks/xRlSK/src/autodiff/chainrules_patch.jl:6
[5] ZBack
@ ~/.julia/packages/Zygote/AlLTp/src/compiler/chainrules.jl:204 [inlined]
[6] Pullback
@ ~/test.jl:16 [inlined]
[7] (::typeof(∂(loss)))(Δ::Float64)
@ Zygote ~/.julia/packages/Zygote/AlLTp/src/compiler/interface2.jl:0
[8] Pullback
@ ~/test.jl:23 [inlined]
[9] (::typeof(∂(#9)))(Δ::Float64)
@ Zygote ~/.julia/packages/Zygote/AlLTp/src/compiler/interface2.jl:0
[10] (::Zygote.var"#55#56"{typeof(∂(#9))})(Δ::Float64)
@ Zygote ~/.julia/packages/Zygote/AlLTp/src/compiler/interface.jl:41
[11] gradient(f::Function, args::Vector{Float64})
@ Zygote ~/.julia/packages/Zygote/AlLTp/src/compiler/interface.jl:76
[12] top-level scope
@ ~/test.jl:23
[13] include(fname::String)
@ Base.MainInclude ./client.jl:444
[14] top-level scope
@ REPL[1]:1
I am not sure if I am doing something wrong here, or whether it is working as intended? Thanks beforehand!
apply!
of its block member.RotationGate
is primitive, for consistency, control block should also be primitive.Ref: #54
Currently only single qubit pauli gate in chain
and prod
supports merging pauli gates.
Composite blocks like kron
and PauliString
with pure Pauli gates can be merged by when inside chain
/prod
as well.
I'll leave this to next release, so we can have some time play with this new optimization pass see what needs to improve.
This is just a reminder to add an AncillasBlock
to this package which add several ancilla qubits and then measure them out.
I defined my own PrimitiveBlock
via
mutable struct MyBlock{T<:Real} <: YaoBlocks.PrimitiveBlock{2}
theta::T
end
and added the neccessary mat, niparams, getiparams, setiparams, Base.adjoint
and cache_key
functions to it. I can use the block just fine in my circuits and
expect(hamiltonian::AbstractBlock, register::AbstractRegister => circuit::ChainBlock)
works also, where circuit
contains MyBlock
instances. However when I try to compute gradients via expect'(hamiltonian, register => circuit)
I get the error message
MethodError: no method matching mat_back!(::Type{Complex{Float64}}, ::MyBlock{Float64}, ::Array{Complex{Float64},2}, ::Array{Any,1})
Closest candidates are:
mat_back!(::Type{T}, ::AbstractBlock, ::Any, ::Any) where T at /home/janlukas/.julia/packages/YaoBlocks/a3uN9/src/autodiff/mat_back.jl:38
mat_back!(::Type{T}, !Matched::RotationGate{N,RT,GT} where GT<:AbstractBlock{N}, ::Any, ::Any) where {T, N, RT} at /home/janlukas/.julia/packages/YaoBlocks/a3uN9/src/autodiff/mat_back.jl:10
mat_back!(::Type{T}, !Matched::TimeEvolution{N,Tt,HT} where HT<:AbstractBlock{N} where Tt, ::Any, ::Any) where {N, T} at /home/janlukas/.julia/packages/YaoBlocks/a3uN9/src/autodiff/mat_back.jl:14
...
I tried writing my own mat_back!
function for the new type like so:
import YaoBlocks.AD.projection
import YaoBlocks.mat_back!
function YaoBlocks.mat_back!(::Type{Complex{T}}, rb::HEVBlock{T}, adjy, collector) where{T}
pushfirst!(collector, projection(rb.theta, adjy .* MyGrad(T, rb)))
end
But the error message persists.
How can I add automatic differentiation functionality to my own parametric blocks?
setiparams!
is not defined for complex arrays?
Also, the error message for is wrong,
ERROR: LoadError: setparams!(x, θ...) is not implemented
should be setiparams!(x, θ...)
like the function name
N = 4
circuit = chain(N)
append!(circuit, [TimeEvolution(put(N, 1=>X), 0.5im)])
dispatch!(circuit, rand(1))
dispatch!(circuit, 1im*rand(1))
Stacktrace:
[1] error(::String) at ./error.jl:33
[2] setiparams!(::TimeEvolution{4,Float64,Complex{Float64},PutBlock{4,1,XGate}}, ::Complex{Float64}) at /home/meach/.julia/packages/YaoBlocks/lIpWc/src/abstract_block.jl:136
[3] setiparams! at /home/meach/.julia/packages/YaoBlocks/lIpWc/src/abstract_block.jl:135 [inlined]
[4] setiparams! at /home/meach/.julia/packages/YaoBlocks/lIpWc/src/abstract_block.jl:145 [inlined]
[5] dispatch!(::Nothing, ::TimeEvolution{4,Float64,Complex{Float64},PutBlock{4,1,XGate}}, ::YaoBlocks.Dispatcher{Array{Complex{Float64},1}}) at /home/meach/.julia/packages/YaoBlocks/lIpWc/src/abstract_block.jl:233
[6] dispatch!(::Nothing, ::ChainBlock{4}, ::YaoBlocks.Dispatcher{Array{Complex{Float64},1}}) at /home/meach/.julia/packages/YaoBlocks/lIpWc/src/abstract_block.jl:235
[7] dispatch!(::Nothing, ::ChainBlock{4}, ::Array{Complex{Float64},1}) at /home/meach/.julia/packages/YaoBlocks/lIpWc/src/abstract_block.jl:251
[8] dispatch!(::ChainBlock{4}, ::Array{Complex{Float64},1}) at /home/meach/.julia/packages/YaoBlocks/lIpWc/src/abstract_block.jl:256
[9] top-level scope at /home/meach/git_projects/QuAlgorithmZoo.jl/mwe.jl:10
[10] include at ./boot.jl:328 [inlined]
[11] include_relative(::Module, ::String) at ./loading.jl:1094
[12] include(::Module, ::String) at ./Base.jl:31
[13] include(::String) at ./client.jl:432
[14] top-level scope at REPL[2]:1
in expression starting at /home/meach/git_projects/QuAlgorithmZoo.jl/mwe.jl:10
I think it's time to move them here now.
I don't think we will revise the design recently even there might be some problem there which should be solve in a more elegant approach by introducing the new IR.
@JuliaRegistrator register()
It looks strange that:
julia> rot(chain(X, X), 0.1)
rot(nqubits: 1, datatype: Complex{Float64}
chain
├─ X gate
└─ X gate, 0.1)
it would be much better if it is just a container
julia> rot(chain(X, X), 0.1)
nqubits: 1, datatype: Complex{Float64}
rot(0.1)
└─ chain
├─ X gate
└─ X gate, 0.1
since composite should simply means the composition of other blocks.
clarify the mathematical meaning of expect'
https://github.com/QuantumBFS/YaoBlocks.jl/blob/master/test/autodiff/specializes.jl#L21
BTW, typo here
https://github.com/QuantumBFS/YaoBlocks.jl/blob/master/test/autodiff/specializes.jl#L43
fideliy
-> fidelity
now with the v0.3 release of IBMQClient, the API should be stable. One could integrate YaoBlocks with IBMQClient by transforming the quantum blocks to the corresponding Qobj schema defined here: https://yaoquantum.org/IBMQClient.jl/dev/schema/
Change mb.result = measure(...)
to
res = measure(...)
if typeof(res) == typeof(mb) && size(res) == size(mb)
mb.result[:] .= res
else
isdefined(res, :result) && warn("Measure result output stream changed! Giveup allocated memory and use new one.")
mb.result = res
end
For two reasons,
creg
can be mapped to a constant address. (or can we use measure block itself as creg
? sounds a bit strange)mb.result
can act as a shared memory between quantum program and classical program.since we are going to move them there
For certain kinds of WF overlap gradients, one would need to conjugate-transpose a unitary that has appeared before, so one needs both the regular and daggered version to appear in the expression (cost or loss function). However, I get errors when using the daggered version.
A minimal reproducing example with even just 1 block, which for now is the non-daggered version, U
:
using Zygote
using Yao
using YaoBlocks
N=2
psi_0 = zero_state(N)
U0 = chain(N, put(1=>Rx(0.0)), put(2=>Ry(0.0)))
C = sum([chain(N, put(k=>Z)) for k=1:N])
function loss(theta)
U = dispatch(U0, theta)
psi0 = copy(psi_0)
psi1 = apply(psi0, U)
psi2 = apply(psi1, C)
result = real(sum(conj(state(psi1)) .* state(psi2)))
return result
end
theta = [1.1,2.2]
println(expect'(C, copy(psi_0) => dispatch(U0, theta))[2])
grad = Zygote.gradient(theta->loss(theta), theta)[1]
println(grad)
In this case, the above loss function computes effectively an expectation value equivalent to expect(C, psi_0 => U)
. Therefore, expect' and zygote.gradient yield the same result [-0.8912073600614354, -0.8084964038195902]
, as expected.
However, if we instead select the conjugate transpose, daggered version, of U, the expect'
version correctly returns the gradient as
julia> expect'(C, copy(psi_0) => dispatch(U0, theta)')[2]
2-element Vector{Float64}:
0.8084964038195901
0.8912073600614354
But when I attempt the same in Zygote by setting psi1 = apply(psi0, U')
we get an error message:
ERROR: LoadError: DimensionMismatch("variable with size(x) == (2,) cannot have a gradient with size(dx) == (1, 2)")
Stacktrace:
[1] (::ChainRulesCore.ProjectTo{AbstractArray, NamedTuple{(:element, :axes), Tuple{ChainRulesCore.ProjectTo{Float64, NamedTuple{(), Tuple{}}}, Tuple{Base.OneTo{Int64}}}}})(dx::Matrix{Float64})
@ ChainRulesCore ~/.julia/packages/ChainRulesCore/7ZiwT/src/projection.jl:226
[2] ProjectTo
@ ~/.julia/packages/ChainRulesCore/7ZiwT/src/projection.jl:247 [inlined]
[3] _project
@ ~/.julia/packages/Zygote/AlLTp/src/compiler/chainrules.jl:182 [inlined]
[4] map(f::typeof(Zygote._project), t::Tuple{Vector{Float64}}, s::Tuple{LinearAlgebra.Adjoint{Float64, Vector{Float64}}})
@ Base ./tuple.jl:232
[5] gradient(f::Function, args::Vector{Float64})
@ Zygote ~/.julia/packages/Zygote/AlLTp/src/compiler/interface.jl:77
[6] top-level scope
@ ~/zygote_bug_reproducer.jl:21
[7] include(fname::String)
@ Base.MainInclude ./client.jl:444
[8] top-level scope
@ REPL[6]:1
in expression starting at /zygote_bug_reproducer.jl:21
I have also tried copying U
first by setting psi1 = apply(psi0, copy(U)')
or psi1 = apply(psi0, copy(U'))
, (because the 'lazy' dagger operation might cause trouble?) but then I think Zygote gets lost tracking parameters across the copied block, because I get another kind of error even if I don't perform the dagger operation but simply psi1 = apply(psi0, copy(U))
:
ERROR: LoadError: Need an adjoint for constructor ChainBlock{2}. Gradient is of type LinearAlgebra.Adjoint{Float64, Vector{Float64}}
any thoughts on how to enable daggered blocks with the Zygote patch? Am I taking the wrong approach, or is it simply defining the correct adjoint/rule like @GiggleLiu did for the other blocks like Add
? is it an issue with double-daggered definitions? Thanks as always!
We have already got batched register for solving the sampling problem.
Also, I find pretty useful to have batched blocks, especially in simulating kernel
quantum algorithms in
Schuld, Maria, and Nathan Killoran. "Quantum machine learning in feature Hilbert spaces." Physical review letters 122.4 (2019): 040504.
A possible prototype
using Yao
struct Batched{N, T, BT<:AbstractBlock{N, T}} <: CompositeBlock{N, T}
blocks::Vector{<:BT}
end
Base.broadcastable(bb::Batched) = bb.blocks
function Yao.apply!(reg::AbstractRegister{B}, bb::Batched) where B
B == length(bb.blocks) || error()
Yao.apply!.(reg, bb)
reg
end
zero_state(4, nbatch=10) |> bb |> state
The problem is how do we dispatch a Batched
block? Or just disallow dispatch!
a scalar for such a block?
can we put the function exp' in YaoBlocks/src/autodiff/specializes.jl to support return the expection and its gridients?
I try this by adding the energy = copy(outδ)'*copy(out), but I feel the parameters or energy dose not change in the iteration.
Is there is something wrong due to the parameters is changed somehow?
iteration and Loss function energy is : 1 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 2 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 3 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 4 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 5 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 6 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 7 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 8 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 9 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 10 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 11 -6.783714426018552 + 0.0im
iteration and Loss function energy is : 12 -6.783714426018552 + 0.0im
I use the optimizier lbfgs. previously before I change the function expect' seems everything ok.
function lbfgs_optimize(circuit::AbstractBlock{N}, hc, niter::Int) where N
iteration = 0
function f(params, grad)
# reg = zero_state(N) |> dispatch!(circuit, params)
_, grad1 = expect'(hc,zero_state(N)=>circuit)
print("grad1 is ",grad1)
for i= 1: length(grad1)
grad[i] = grad1[i]
end
loss = expect(hc, reg) |> real
println("Loss function is", loss)
iteration += 1
loss
end
opt = Opt(:LD_LBFGS, nparameters(circuit))
min_objective!(opt, f)
maxeval!(opt, niter)
cost, params, info = optimize(opt, parameters(circuit))
print("info is", info)
cost, params, info, iteration
end
This is the origin expect' function(except the comment)
function (::Adjoint{Any,typeof(expect)})(op::AbstractBlock, circuit::Pair{<:ArrayReg,<:AbstractBlock})
reg, c = circuit
#println("try to modify")
out = copy(reg) |> c
outδ = copy(out) |> op
#energy = copy(outδ)'copy(out)
#println("energy is ", energy)
(in, inδ), paramsδ = apply_back((out, outδ), c)
return inδ => paramsδ . 2
end
the error behaviour is a bit unintuitive, it is safer to leave parameters unchanged instead of
julia> g = chain(Rx(0.1), Ry(0.2))
nqubits: 1, datatype: Complex{Float64}
chain
├─ rot(X gate, 0.1)
└─ rot(Y gate, 0.2)
julia> dispatch!(g, (0.2, ))
ERROR: BoundsError: attempt to access (0.2,)
at index [2]
Stacktrace:
[1] getindex at ./tuple.jl:24 [inlined]
[2] getindex at ./range.jl:292 [inlined]
[3] consume! at /Users/roger/.julia/dev/YaoBlocks/src/abstract_block.jl:211 [inlined]
[4] dispatch!(::Nothing, ::RotationGate{1,Float64,YGate{Complex{Float64}}}, ::YaoBlocks.Dispatcher{Tuple{Float64}}) at /Users/roger/.julia/dev/YaoBlocks/src/abstract_block.jl:225
[5] dispatch!(::Nothing, ::ChainBlock{1,Complex{Float64}}, ::YaoBlocks.Dispatcher{Tuple{Float64}}) at /Users/roger/.julia/dev/YaoBlocks/src/abstract_block.jl:227
[6] dispatch!(::Nothing, ::ChainBlock{1,Complex{Float64}}, ::Tuple{Float64}) at /Users/roger/.julia/dev/YaoBlocks/src/abstract_block.jl:234
[7] dispatch!(::ChainBlock{1,Complex{Float64}}, ::Tuple{Float64}) at /Users/roger/.julia/dev/YaoBlocks/src/abstract_block.jl:239
[8] top-level scope at none:0
julia> g
nqubits: 1, datatype: Complex{Float64}
chain
├─ rot(X gate, 0.2)
└─ rot(Y gate, 0.2)
XRef: #31
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.