Open Krastanov opened 3 years ago
Ideally interoperability would not require creating a dependency on a large complicated external package. This is one of my main worries as I am particularly happy how small QuantumClifford
is.
Thanks for being interested in this!
It can be particularly fast because this restricted set of circuits have efficient classical representations.
~I'm wondering for the circuit simulation, does it use the tableau algorithm or the graph state algorithm, or it's something new? Just out of curiosity.~ I just realize it is the tableau algorithm, it's nice to see an implementation for this! and just FYI. the graph state algorithm can be performed and generalized in ZX diagram so we can use ZXCalculus.jl to do efficient simulation in principal.
My questions is, what is the appropriate way to ensure circuits represented by YaoBlocks work in this simulator? Could you point me to a design document that describes expected interfaces for instance? Or just write down some mock Julia REPL session you expect to be possible in your favorite interoperable future.
To provide a new backend you need don't need to worry about YaoBlocks at all. Just create a new register type would do the work, which can be just put into a glue package, e.g we can create package called YaoQuantumClifford.jl
contains
struct CliffordReg <: YaoAPI.AbstractRegister{1} # 1 means the batch size is always 1
state::Stabilizer # I assume you use struct Stabilizer to represent your state?
end
YaoBase.nqubits(s::CliffordReg) = # number of total qubits
YaoBase.nactive(s::CliffordReg) = nqubits(s) # in the Clifford case I guess we don't have this concept so let's make all qubits active
then you just implement the YaoAPI.instruct!
interface which is simply
function YaoAPI.instruct!(r::CliffordReg, gate, locs::NTuple{N, Int}) where N
# I'm not sure if the apply! function accepts Tuple as locations yet
QuantumClifford.apply!(r.state, gate, locs)
return r # remember to return the register object
end
OK this is basically it! I'm not sure what is s
in your README example, so I didn't run the above code, but basically you just put whatever is s
into the CliffordReg
type. The rest of the Yao ecosystem should just work.
(we will fix things if there are corner cases that doesn't work as we expected, but I think in principal it should just work)
Thanks, this is very informative! Yes, indeed, it is simply the tableaux formalism (with the "destabilizer" secondary tableaux also implemented in order to further speed up some of the operations).
I have a couple of extra questions:
gate
supposed to be in instruct!
? Is there "one true set of gates"?I saw your edit concerning ZXCalculus
. Could you give a simple example against which I can benchmark to see whether QuantumClifford
can provide anything of use? For instance, how would I generate a circuit of 50 CNOT gates acting on 80 qubits initialized in some states and then measure 20 different multiqubit Pauli operators. The examples I see in ZXCalculus deal more with simplifying circuits and not that much with simulating the result of particular measurements (maybe I missed the pertinent examples).
How do you deal with "trajectories"-style simulations or Monte Carlo simulations? In such cases the output of the instruction would have different possible values and some form of reduction over that set will be necessary.
How do you represent noisy hardware? For instance, a gate that has some chance to depolarize the qubit or measurement that has some chance to fail.
For these two problems, unfortunately, we haven't thought about it during the design of the current QBIR. QBIR serves more as a pure unitary quantum operation plus measure, which as a result we can only represent unitary channels in this IR.
However, we are working on a new type of IR in the compiler YaoCompiler for YaoLang, which utilizes Julia's SSA IR (and in the future MLIR) for representing hybrid programs, which will contain a more unified IR that provides the representation of gates, channels, and pulse. This would further provide simpler and sugary syntax and unleash Julia on real hardware.
For trajectory simulations, we haven't work on related simulators yet. But since our representation of circuits is decoupled from the register (both QBIR and YaoLang), that means instead of using a register type, for simulation, we can ask for a sample(circuit)
to generate the sample, where the evaluation of MC probability is done by contracting gates at given indices on input and output. However, I'm not able to give you many details on this direction, since MC based simulation is something we haven't carefully thought about.
Regarding noise channels, in YaoLang, it will be a parameterized primitive function depolarize(lambda)
which will be dispatched to the instruct!(state_or_density, Val(:depolarize), locs, lambda)
where the density matrix or state vector simulator are dispatched by different types of the state. But this is still under development.
What is gate supposed to be in instruct!? Is there "one true set of gates"?
the gate
argument in instruct!
can be anything. Sorry if you were misled by using the name gate, but it should be operator
in this sense. Since it is more like a middle interface to dispatch to different backends in runtime. Thus what's the gate
argument exactly does not matter, but the type matters (for dispatch).
For primitive gates, we usually use Val{:X}
to dispatch this low-level interface, or for the general matrix, we use AbstractMatrix
, but you can always specialize it on a different type for needs. However, all the primitive gates in YaoBlocks will be dispatched to Val{:gate_name}
by default, e.g apply!(r, put(3=>X)
will be dispatched instruct!(r.state, Val(:X), (3, ))
you should be able to find all the primitive gates here: https://github.com/QuantumBFS/YaoBlocks.jl/tree/master/src/primitive
and for reference how full amplitude simulator is implemented, here is how applying X gate on given locations is defined: https://github.com/QuantumBFS/YaoArrayRegister.jl/blob/master/src/instruct.jl#L226
and here is how CNOT-like gate is defined (multi or single controlled-X): https://github.com/QuantumBFS/YaoArrayRegister.jl/blob/master/src/instruct.jl#L413
The examples I see in ZXCalculus deal more with simplifying circuits and not that much with simulating the result of particular measurements (maybe I missed the pertinent examples).
Yes, we made it for circuit simplification. Since we don't have a use case to implement an efficient algorithm for Clifford circuits ourselves, so we never actually implement an interface for this.
I didn't mean to benchmark these two, but more just want to mention that the graph state algorithm actually exists in ZX calculus, I'm not sure if it is useful for you, but in case it does. Imagine when you input state is represented in a ZX-diagram, then we will be able to contract the input state diagram with the circuit diagram and simplify it which gives you the ZX-diagram of the final state. Here is a sketch of how you can calculate the result of a GHZ circuit directly
Thank you, I have a much better understanding now. I will try to keep up with Yao's development.
The simulation of noisy Clifford circuits (e.g. the Monte Carlo and the symbolic derivation of values for various metrics) is a particularly important goal of my project, which does not seem to be yet covered by the IR available here. I am looking forward to the next gen IR you mentioned, it sounds very ambitious and very interesting.
I agree about the ZX calculus being able to efficiently deal with Clifford circuits, but I expect it to be a bit slower simply due to the nature of its algorithm: transforming graphs is more difficult to do in a SIMD manner than the simple linear algebra involved in the typical tableaux. I am curious to see whether the difference matters (julia frequently surprises me in what it can optimize).
Related: Work on using QuantumClifford.jl
as a possible backend for Yao is being done here: https://github.com/QuantumBFS/YaoClifford.jl
But more to the point of this issue: @Roger-luo , how feasible would it be to extract the library of gate names currently in Yao into a separate package that can be used without any of the functionality of Yao. The reason I am asking is that I would prefer if there is only one true list of gate names that can be used by different Julia packages, like the many other AbstractSomethingInterface
packages available. I would prefer if in my package I can do something like import AbstractQuantumInterfaces
and have a struct XGate
, instead of creating yet another list of gates with slightly different naming conventions. But, naturally, I do not need any actual Yao functionality in my otherwise unrelated package.
For YaoBlocks, I think you can always traverse the expression tree to get the list of gate names. But I don't we are able to split functionalities from YaoBlocks anymore since the code is quite stable and relatively entangled so it's gonna be hard to do so.
As for a more independent intermediate representation, YaoHIR might be something you are looking for, it is much simpler than YaoBlocks, but it is quite WIP, it is designed as an IR between different things such as compiler and backends.
The package itself is quite lightweight, it only defines the intrinsic objects in YaoIR.IntrinsicOperation
and one simple composite node Chain
This is also the product of OpenQASM parser from YaoCompiler, or the input of IBM Q backend etc.
Thanks! For the moment I will try to at least keep the naming conventions the same as the ones you have established for Yao (it would probably not be always possible). It does not seem AbstractQuantumInterfaces
would really be a thing that can spin off from YaoBlocks in the near term.
Thanks! For the moment I will try to at least keep the naming conventions the same as the ones you have established for Yao (it would probably not be always possible).
Thanks, I think at least the conceptual convention should be very stable around Yao packages.
I am prompted to ask this question by an offhand comment @Roger-luo made in https://discourse.julialang.org/t/quantikz-jl-for-drawing-quantum-circuit-diagrams-with-julia/52200 I am working on a library with a very limited scope: fast simple simulation of Clifford circuits. It is QuantumClifford.jl. It can be particularly fast because this restricted set of circuits have efficient classical representations. One neat extra feature is that it has a both a Monte Carlo and a symbolic algebra estimator for the output of noisy Clifford circuits. This package is registered, but it is still rather young and has not been announced. I might be announcing it in the next few days.
My questions is, what is the appropriate way to ensure circuits represented by YaoBlocks work in this simulator? Could you point me to a design document that describes expected interfaces for instance? Or just write down some mock Julia REPL session you expect to be possible in your favorite interoperable future.
Also, feel free to correct me if you do not think this really fits. Maybe YaoBlocks are not meant to represent that type of circuits and that type of states.