Abstract Registers
Quantum circuits process quantum states. A quantum state being processing by a quantum circuit will be stored on a quantum register. In Yao we provide several types for registers. The default type for registers is the ArrayReg
which is defined in YaoArrayRegister.jl.
The registers can be extended by subtyping AbstractRegister
and define correspinding register interfaces defined in YaoBase.jl, which includes:
Minimal Required Interfaces
The following interfaces are the minial required interfaces to make a register's printing work and be able to accept certain gates/blocks.
But if you don't want to work with our default printing, you could define your custom printing with Base.show
.
YaoBase.nqubits
— Function.YaoBase.nactive
— Function.nactive(register) -> Int
Returns the number of active qubits.
Operators always apply on active qubits.
you can define instruct!
, to provide specialized instructions for the registers from plain storage types.
Qubit Management Interfaces
YaoBase.addbits!
— Function.addbits!(register, n::Int) -> register
addbits!(n::Int) -> λ(register)
Add n
qubits to given register in state |0>. i.e. |psi> -> |000> ⊗ |psi>, increased bits have higher indices.
If only an integer is provided, then returns a lambda function.
YaoBase.reorder!
— Function.reorder!(reigster, orders)
Reorder the locations of register by input orders.
Qubit Scope Management Interfaces
LDT format
Concepturely, a wave function $|\psi\rangle$ can be represented in a low dimentional tensor (LDT) format of order-3, L(f, r, b).
- f: focused (i.e. operational) dimensions
- r: remaining dimensions
- b: batch dimension.
For simplicity, let's ignore batch dimension for the now, we have
Given a configuration x
(in operational space), we want get the i-th bit using (x<<i) & 0x1
, which means putting the small end the qubit with smaller index. In this representation L(x)
will get return $\langle x|\psi\rangle$.
Why not the other convension: Using the convention of putting 1st bit on the big end will need to know the total number of qubits n
in order to know such positional information.
HDT format
Julia storage is column major, if we reshape the wave function to a shape of $2\times2\times ... \times2$ and get the HDT (high dimensional tensor) format representation H, we can use H($x_1, x_2, ..., x_3$) to get $\langle x|\psi\rangle$.
YaoBase.focus!
— Function.focus!(register, locs) -> register
Focus the wires on specified location.
Example
julia> focus!(r, (1, 2, 4))
focus!(locs...) -> f(register) -> register
Lazy version of focus!
, this returns a lambda which requires a register.
focus(f, register, locs...)
Call a callable f
under the context of focus
. See also focus!
.
Example
print the focused register
julia> r = ArrayReg(bit"101100")
ArrayReg{1,Complex{Float64},Array...}
active qubits: 6/6
julia> focus(x->(println(x);x), r, 1, 2);
ArrayReg{1,Complex{Float64},Array...}
active qubits: 2/6
YaoBase.relax!
— Function.relax!(register[, locs]; to_nactive=nqubits(register)) -> register
Inverse transformation of focus!
, where to_nactive
is the number of active bits for target register.
relax!(locs::Int...; to_nactive=nqubits(register)) -> f(register) -> register
Lazy version of relax!
, it will be evaluated once you feed a register to its output lambda.
Measurement Interfaces
YaoBase.measure
— Function.YaoBase.measure!
— Function.measure!([operator, ]register[, locs])
Measure current active qubits or qubits at locs
and collapse to result state.
YaoBase.measure_remove!
— Function.measure_remove!([operator, ]reg::AbstractRegister[, locs])
Measure current active qubits or qubits at locs
and remove them.
YaoBase.measure_collapseto!
— Function.measure_collapseto!([operator, ]reg::AbstractRegister[, locs]; config) -> Int
Measure current active qubits or qubits at locs
and set the register to specific value.
YaoBase.select!
— Function.select!(dest::AbstractRegister, src::AbstractRegister, bits::Integer...) -> AbstractRegister
select!(register::AbstractRegister, bits::Integer...) -> register
select a subspace of given quantum state based on input eigen state bits
. See also select
.
Example
select!(reg, 0b110)
will select the subspace with (focused) configuration 110
. After selection, the focused qubit space is 0, so you may want call relax!
manually.
Developers should overload select!(r::RegisterType, bits::NTuple{N, <:Integer})
and do not assume bits
has specific number of bits (e.g Int64
), or it will restrict the its maximum available number of qubits.
Others
YaoBase.fidelity
— Function.fidelity(register1, register2)
Return the fidelity between two states.
Definition
The fidelity of two quantum state for qubits is defined as:
Or its equivalent form (which we use in numerical calculation):
Reference
- Jozsa R. Fidelity for mixed quantum states[J]. Journal of modern optics, 1994, 41(12): 2315-2323.
- Nielsen M A, Chuang I. Quantum computation and quantum information[J]. 2002.
The original definition of fidelity $F$ was from "transition probability", defined by Jozsa in 1994, it is the square of what we use here.
fidelity(r1::ArrayReg, r2::ArrayReg)
Calcuate the fidelity between r1
and r2
, if r1
or r2
is not pure state (nactive(r) != nqubits(r)
), the fidelity is calcuated by purification. See also pure_state_fidelity
, purification_fidelity
.
YaoBase.tracedist
— Function.tracedist(register1, register2)
Return the trace distance of register1
and register2
.
Definition
Trace distance is defined as following:
Reference
- https://en.wikipedia.org/wiki/Trace_distance
YaoBase.density_matrix
— Function.density_matrix(register)
Returns the density matrix of current active qubits.
YaoBase.viewbatch
— Function.viewbatch(register, i::Int) -> AbstractRegister{1}
Returns a view of the i-th slice on batch dimension.