Quantum Registers

A quantum register is a quantum state or a batch of quantum states. Yao provides two types of quantum registers ArrayReg and BatchedArrayReg.

Missing docstring.

Missing docstring for AbstractArrayReg. Check Documenter's build log for details.

YaoArrayRegister.ArrayRegType
ArrayReg{D,T,MT<:AbstractMatrix{T}} <: AbstractArrayRegister{D}
ArrayReg{D}(raw)
ArrayReg(raw::AbstractVecOrMat; nlevel=2)
ArrayReg(r::ArrayReg)

Simulated full amplitude register type, it uses an array to represent corresponding one or a batch of quantum states. T is the numerical type for each amplitude, it is ComplexF64 by default.

Warning

ArrayReg constructor will not normalize the quantum state. If you need a normalized quantum state remember to use normalize!(register) on the register or normalize the input raw array with normalize or batched_normalize!.

source
YaoArrayRegister.BatchedArrayRegType
BatchedArrayReg{D,T,MT<:AbstractMatrix{T}} <: AbstractArrayReg{D}
BatchedArrayReg(raw, nbatch; nlevel=2)
BatchedArrayReg{D}(raw, nbatch)

Simulated batched full amplitude register type, it uses an array to represent corresponding one or a batch of quantum states. T is the numerical type for each amplitude, it is ComplexF64 by default.

Warning

BatchedArrayReg constructor will not normalize the quantum state. If you need a normalized quantum state remember to use normalize!(register) on the register or normalize the input raw array with normalize or batched_normalize!.

source

We define some shortcuts to create simulated quantum states easier:

YaoArrayRegister.arrayregFunction
arrayreg(state; nbatch::Union{Integer,NoBatch}=NoBatch(), nlevel::Integer=2)

Create an array register, if nbatch is a integer, it will return a BatchedArrayReg.

source
arrayreg([T=ComplexF64], bit_str; nbatch=NoBatch())

Construct an array register from bit string literal. For bit string literal please read @bit_str.

Examples

julia> arrayreg(bit"1010")
ArrayReg{2, ComplexF64, Array...}
    active qubits: 4/4
    nlevel: 2

julia> arrayreg(ComplexF32, bit"1010")
ArrayReg{2, ComplexF32, Array...}
    active qubits: 4/4
    nlevel: 2
source
YaoArrayRegister.product_stateFunction
product_state([T=ComplexF64], dit_str; nbatch=NoBatch(), no_transpose_storage=false)
product_state([T=ComplexF64], nbits::Int, val::Int; nbatch=NoBatch(), nlevel=2, no_transpose_storage=false)
product_state([T=ComplexF64], vector; nbatch=NoBatch(), nlevel=2, no_transpose_storage=false)

Create an ArrayReg of product state. The configuration can be specified with a dit string, which can be defined with @bit_str or @dit_str. Or equivalently, it can be specified explicitly with nbits, val and nlevel. See also zero_state, rand_state, uniform_state.

Examples

julia> reg = product_state(dit"120;3"; nbatch=2)
BatchedArrayReg{3, ComplexF64, Transpose...}
    active qudits: 3/3
    nlevel: 3
    nbatch: 2

julia> measure(reg)
1×2 Matrix{BitBasis.DitStr64{3, 3}}:
 120 ₍₃₎  120 ₍₃₎

julia> product_state(bit"100"; nbatch=2);

julia> r1 = product_state(ComplexF32, bit"001"; nbatch=2);

julia> r2 = product_state(ComplexF32, [1, 0, 0]; nbatch=2);

julia> r3 = product_state(ComplexF32, 3, 0b001; nbatch=2);

julia> r1 ≈ r2   # because we read bit strings from right to left, vectors from left to right.
true

julia> r1 ≈ r3
true
source
YaoArrayRegister.zero_stateFunction
zero_state([T=ComplexF64], n::Int; nbatch::Int=NoBatch())

Create an AbstractArrayReg that initialized to state $|0\rangle^{\otimes n}$. See also product_state, rand_state, uniform_state and ghz_state.

Examples

julia> zero_state(4)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 4/4
    nlevel: 2

julia> zero_state(ComplexF32, 4)
ArrayReg{2, ComplexF32, Array...}
    active qubits: 4/4
    nlevel: 2

julia> zero_state(ComplexF32, 4; nbatch=3)
BatchedArrayReg{2, ComplexF32, Transpose...}
    active qubits: 4/4
    nlevel: 2
    nbatch: 3
source
YaoArrayRegister.zero_state_likeFunction
zero_state_like(register, n) -> AbstractRegister

Create a register initialized to zero from an existing one.

Examples

julia> reg = rand_state(3; nbatch=2);

julia> zero_state_like(reg, 2)
BatchedArrayReg{2, ComplexF64, Array...}
    active qubits: 2/2
    nlevel: 2
    nbatch: 2
source
YaoArrayRegister.rand_stateFunction
rand_state([T=ComplexF64], n::Int; nbatch=NoBatch(), no_transpose_storage=false)

Create a random AbstractArrayReg with total number of qudits n.

Examples

julia> rand_state(4)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 4/4
    nlevel: 2

julia> rand_state(ComplexF64, 4)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 4/4
    nlevel: 2

julia> rand_state(ComplexF64, 4; nbatch=2)
BatchedArrayReg{2, ComplexF64, Transpose...}
    active qubits: 4/4
    nlevel: 2
    nbatch: 2
source
YaoArrayRegister.uniform_stateFunction
uniform_state([T=ComplexF64], n; nbatch=NoBatch(), no_transpose_storage=false)

Create a uniform state:

\[\frac{1}{\sqrt{2^n}} \sum_{k=0}^{2^{n}-1} |k\rangle.\]

This state can also be created by applying H (Hadmard gate) on $|00⋯00⟩$ state.

Example

julia> uniform_state(4; nbatch=2)
BatchedArrayReg{2, ComplexF64, Transpose...}
    active qubits: 4/4
    nlevel: 2
    nbatch: 2

julia> uniform_state(ComplexF32, 4; nbatch=2)
BatchedArrayReg{2, ComplexF32, Transpose...}
    active qubits: 4/4
    nlevel: 2
    nbatch: 2
source
YaoArrayRegister.ghz_stateFunction
ghz_state([T=ComplexF64], n::Int; nbatch::Int=NoBatch())

Create a GHZ state (or a cat state) that defined as

\[\frac{|0\rangle^{\otimes n} + |1\rangle^{\otimes n}}{\sqrt{2}}.\]

Examples

julia> ghz_state(4)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 4/4
    nlevel: 2
source
YaoAPI.cloneFunction
clone(register, n)

Create an ArrayReg by cloning the original register for n times on batch dimension. This function is only for emulation.

Example

julia> clone(arrayreg(bit"101"; nbatch=3), 4)
BatchedArrayReg{2, ComplexF64, Array...}
    active qubits: 3/3
    nlevel: 2
    nbatch: 12
source

In a register, qubits are distinguished as active and inactive (or remaining). The total number of qubits is the number of active qubits plus the number of remaining qubits. Only active qubits are visible to quantum operators and the number of these qubits are the size of a register. Making this distinction of qubits allows writing reusable quantum circuits. For example, Suppose we want to run a quantum Fourier transformation circuit of size 4 on qubits (1, 3, 5, 7), we first set the target qubits to active qubits the reset to inactive, then we apply the circuit on it, finally we unset the inactive qubits.

YaoAPI.nquditsFunction
nqudits(register) -> Int

Returns the total number of qudits in register.

source
YaoAPI.nactiveFunction
nactive(register) -> Int

Returns the number of active qudits in register. Here, active qudits means the system qubits that operators can be applied on.

source
Missing docstring.

Missing docstring for nbatch, nlevel, focus!. Check Documenter's build log for details.

YaoAPI.focusFunction
focus(f, register, locs)

Call a callable f under the context of focus. See also focus!.

Examples

To print the focused register

julia> r = arrayreg(bit"101100")
ArrayReg{2, ComplexF64, Array...}
    active qubits: 6/6
    nlevel: 2

julia> focus(x->(println(x);x), r, (1, 2));
ArrayReg{2, ComplexF64, Array...}
    active qubits: 2/6
    nlevel: 2
source
YaoAPI.relax!Function
relax!(register[, locs]; to_nactive=nqudits(register)) -> register
relax!(locs::Int...; to_nactive=nqudits(register)) -> f(register) -> register

Inverse transformation of focus!, where to_nactive is the number of active bits for target register. If the register is not provided, returns a lambda function that takes a register as input.

Examples

julia> reg = product_state(bit"01101")
ArrayReg{2, ComplexF64, Array...}
    active qubits: 5/5
    nlevel: 2

julia> focus!(reg, (1,3,4))
ArrayReg{2, ComplexF64, Array...}
    active qubits: 3/5
    nlevel: 2

julia> relax!(reg, (1,3,4))
ArrayReg{2, ComplexF64, Array...}
    active qubits: 5/5
    nlevel: 2
source
Missing docstring.

Missing docstring for zero_state. Check Documenter's build log for details.

YaoArrayRegister.exchange_sysenvFunction
exchange_sysenv(reg::AbstractArrayReg) -> AbstractRegister

Exchange system (focused qubits) and environment (remaining qubits).

julia> reg = rand_state(5)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 5/5
    nlevel: 2

julia> focus!(reg, (2,4))
ArrayReg{2, ComplexF64, Array...}
    active qubits: 2/5
    nlevel: 2

julia> exchange_sysenv(reg)
ArrayReg{2, ComplexF64, Adjoint...}
    active qubits: 3/5
    nlevel: 2
source

Storage

Both ArayReg and BatchedArrayReg use matrices as the storage. For example, for a quantum register with $a$ active qubits, $r$ remaining qubits and batch size $b$, the storage is as follows

The first dimension of size $2^a$ is for active qubits, only this subset of qubits are allowed to interact with blocks. Since we reshaped the state vector into a matrix, applying a quantum operator can always be represented as a matrix-matrix multiplication . In practice, most gates have in-place implementation that does not require constructing the operator matrix explicitly.

You can access different views of the storage of an ArrayReg with the following functions:

YaoArrayRegister.stateFunction
state(register::AbstractArrayReg) -> Matrix

Returns the raw array storage of register. See also statevec.

source
state(ρ::DensityMatrix) -> Matrix

Return the raw state of density matrix ρ.

source
BitBasis.basisFunction
basis(ditstr) -> UnitRange{DitStr{D,N,T}}
basis(DitStr{D,N,T}) -> UnitRange{DitStr{D,N,T}}

Returns the UnitRange for basis in Hilbert Space of qudits.

basis(register) -> UnitRange

Returns an UnitRange of the all the bits in the Hilbert space of given register.

julia> collect(basis(rand_state(3)))
8-element Vector{DitStr{2, 3, Int64}}:
 000 ₍₂₎
 001 ₍₂₎
 010 ₍₂₎
 011 ₍₂₎
 100 ₍₂₎
 101 ₍₂₎
 110 ₍₂₎
 111 ₍₂₎
source
YaoArrayRegister.statevecFunction
statevec(r::ArrayReg) -> array

Return a state matrix/vector by droping the last dimension of size 1 (i.e. nactive(r) = nqudits(r)). See also state.

Warning

statevec is not type stable. It may cause performance slow down.

source
BitBasis.hypercubicFunction
hypercubic(A::Array) -> Array

get the hypercubic representation for an array.

hypercubic(r::ArrayReg) -> AbstractArray

Return the hypercubic representation (high dimensional tensor) of this register, only active qudits are considered. See also rank3 and state.

source
YaoAPI.viewbatchFunction
viewbatch(register, i::Int) -> AbstractRegister

Returns the i-th single register of a batched register. The returned instance is a view of the original register, i.e. inplace operation changes the original register directly.

Examples

julia> reg = zero_state(5; nbatch=2);

julia> apply!(viewbatch(reg, 2), put(5, 2=>X));

julia> measure(reg; nshots=3)
3×2 Matrix{DitStr{2, 5, Int64}}:
 00000 ₍₂₎  00010 ₍₂₎
 00000 ₍₂₎  00010 ₍₂₎
 00000 ₍₂₎  00010 ₍₂₎
source
YaoArrayRegister.transpose_storageFunction
transpose_storage(register) -> register

Transpose the register storage. Sometimes transposed storage provides better performance for batched simulation.

source

Operations

The list of arithmetic operations for ArrayReg include

  • +
  • -
  • *
  • / (scalar)
  • adjoint

Then the inner product can be computed as follows.

julia> reg = rand_state(3);

julia> reg' * reg
0.9999999999999998 + 0.0im
Missing docstring.

Missing docstring for AdjointArrayReg. Check Documenter's build log for details.

We also have some faster inplace versions of arithematic operations

Missing docstring.

Missing docstring for regadd!, regsub!, regscale!,. Check Documenter's build log for details.

We also define the following functions for state normalization, and distance measurement.

LinearAlgebra.normalize!Function
normalize!(r::AbstractArrayReg)

Normalize the register r by its 2-norm. It changes the register directly.

Examples

The following code creates a normalized GHZ state.

julia> reg = product_state(bit"000") + product_state(bit"111");

julia> norm(reg)
1.4142135623730951

julia> isnormalized(reg)
false

julia> normalize!(reg);

julia> isnormalized(reg)
true
source
YaoAPI.fidelityFunction
fidelity(register1, register2) -> Real/Vector{<:Real}
fidelity'(pair_or_reg1, pair_or_reg2) -> (g1, g2)

Return the fidelity between two states. Calcuate the fidelity between r1 and r2, if r1 or r2 is not pure state (nactive(r) != nqudits(r)), the fidelity is calcuated by purification. See also pure_state_fidelity, purification_fidelity.

Obtain the gradient with respect to registers and circuit parameters. For pair input ψ=>circuit, the returned gradient is a pair of gψ=>gparams, with the gradient of input state and gparams the gradients of circuit parameters. For register input, the return value is a register.

Definition

The fidelity of two quantum state for qudits is defined as:

\[F(ρ, σ) = tr(\sqrt{\sqrt{ρ}σ\sqrt{ρ}})\]

Note

This definition is different from the one in Wiki by a square.

Examples

julia> reg1 = uniform_state(3);

julia> reg2 = zero_state(3);

julia> fidelity(reg1, reg2)
0.35355339059327373

References

  • 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.
Note

The original definition of fidelity $F$ was from "transition probability", defined by Jozsa in 1994, it is the square of what we use here.

source
YaoAPI.tracedistFunction
tracedist(register1, register2)

Return the trace distance of register1 and register2.

Definition

Trace distance is defined as following:

\[\frac{1}{2} || A - B ||_{\rm tr}\]

Examples

julia> reg1 = uniform_state(3);

julia> reg2 = zero_state(3);

julia> tracedist(reg1, reg2)
1.8708286933869704

References

  • https://en.wikipedia.org/wiki/Trace_distance
source

Resource management and addressing

Missing docstring.

Missing docstring for add_qudits!. Check Documenter's build log for details.

Missing docstring.

Missing docstring for add_qubits!. Check Documenter's build log for details.

YaoAPI.append_qudits!Function
append_qudits!(register, n::Int) -> register
append_qudits!(n::Int) -> λ(register)

Add n qudits 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.

Examples

julia> reg = product_state(bit"01101")
ArrayReg{2, ComplexF64, Array...}
    active qubits: 5/5
    nlevel: 2

julia> append_qudits!(reg, 2)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 7/7
    nlevel: 2

julia> measure(reg; nshots=3)
3-element Vector{DitStr{2, 7, Int64}}:
 0001101 ₍₂₎
 0001101 ₍₂₎
 0001101 ₍₂₎

Note here, we read the bit string from right to left.

source
YaoAPI.append_qubits!Function
append_qubits!(register, n::Int) -> register
append_qubits!(n::Int) -> λ(register)

Add n qudits to given register in state |0>. It is an alias of append_qudits! function.

source
YaoAPI.reorder!Function
reorder!(reigster, orders)

Reorder the locations of register by input orders. For a 3-qubit register, an order (i, j, k) specifies the following reordering of qubits

  • move the first qubit go to i,
  • move the second qubit go to j,
  • move the third qubit go to k.
Note

The convention of reorder! is different from the permutedims function, one can use the sortperm function to relate the permutation order and the order in this function.

Examples

julia> reg = product_state(bit"010101");

julia> reorder!(reg, (1,4,2,5,3,6));

julia> measure(reg)
1-element Vector{DitStr{2, 6, Int64}}:
 000111 ₍₂₎
source
YaoAPI.invorder!Function
invorder!(register)

Inverse the locations of the register.

Examples

julia> reg = product_state(bit"010101")
ArrayReg{2, ComplexF64, Array...}
    active qubits: 6/6
    nlevel: 2

julia> measure(invorder!(reg); nshots=3)
3-element Vector{DitStr{2, 6, Int64}}:
 101010 ₍₂₎
 101010 ₍₂₎
 101010 ₍₂₎
source

Only a subset of qubits that does not interact with other qubits can be removed, the best approach is first measuring it in computational basis first. It can be done with the measure! function by setting the first argument to RemoveMeasured().

Instruction set

Although we have matrix representation for Yao blocks, specialized instructions are much faster and memory efficient than using the matrix-matrix product. These instructions are specified with the instruct! function listed bellow.

YaoAPI.instruct!Function
instruct!([nlevel=Val(2), ]state, operator, locs[, control_locs, control_configs, theta])

Unified interface for applying an operator to a quantum state. It modifies the state directly.

Arguments

  • nlevel is the number of levels in each qudit,
  • state is a vector or matrix representing the quantum state, where the first dimension is the active qubit dimension, the second is the batch dimension.
  • operator is a quantum operator, which can be Val(GATE_SYMBOL) or a matrix.
  • locs::Tuple is a tuple for specifying the locations this gate applied.
  • control_locs::Tuple and control_configs are tuples for specifying the control locations and control values.
  • theta::Real is the parameter for the gate, e.g. Val(:Rx) gate takes a real number of its parameter.
source

Measurement

We have a true measure function measure! that collapses the state after the measurement. We also have some "cheating" functions to facilitate classical simulation.

YaoAPI.measure!Function
measure!([postprocess,] [operator, ]register[, locs]; rng=Random.GLOBAL_RNG)

Measure current active qudits or qudits at locs. If the operator is not provided, it will measure on the computational basis and collapse to a product state. Otherwise, the quantum state collapse to the subspace corresponds to the resulting eigenvalue of the observable.

Arguments

  • postprocess is the postprocessing method, it can be
    • NoPostProcess() (default).
    • ResetTo(config), reset to result state to config. It can not be used if operator is provided, because measuring an operator in general does not return a product state.
    • RemoveMeasured(), remove the measured qudits from the register. It is also incompatible with the operator argument.
  • operator::AbstractBlock is the operator to measure.
  • register::AbstractRegister is the quantum state.
  • locs is the qubits to performance the measurement. If locs is not provided, all current active qudits are measured (regarding to active qudits,

see focus! and relax!).

Keyword arguments

  • rng is the random number generator.

Examples

The following example measures a random state on the computational basis and reset it to a certain bitstring value.

julia> reg = rand_state(3);

julia> measure!(ResetTo(bit"011"), reg)
110 ₍₂₎

julia> measure(reg; nshots=3)
3-element Vector{DitStr{2, 3, Int64}}:
 011 ₍₂₎
 011 ₍₂₎
 011 ₍₂₎

julia> measure!(RemoveMeasured(), reg, (1,2))
11 ₍₂₎

julia> reg  # removed qubits are not usable anymore
ArrayReg{2, ComplexF64, Array...}
    active qubits: 1/1
    nlevel: 2

Measuring an operator will project the state to the subspace associated with the returned eigenvalue.

julia> reg = uniform_state(3)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 3/3
    nlevel: 2

julia> print_table(reg)
000 ₍₂₎   0.35355 + 0.0im
001 ₍₂₎   0.35355 + 0.0im
010 ₍₂₎   0.35355 + 0.0im
011 ₍₂₎   0.35355 + 0.0im
100 ₍₂₎   0.35355 + 0.0im
101 ₍₂₎   0.35355 + 0.0im
110 ₍₂₎   0.35355 + 0.0im
111 ₍₂₎   0.35355 + 0.0im

julia> measure!(repeat(3, Z, 1:3), reg)
-1.0 + 0.0im

julia> print_table(reg)
000 ₍₂₎   0.0 + 0.0im
001 ₍₂₎   0.5 + 0.0im
010 ₍₂₎   0.5 + 0.0im
011 ₍₂₎   0.0 + 0.0im
100 ₍₂₎   0.5 + 0.0im
101 ₍₂₎   0.0 + 0.0im
110 ₍₂₎   0.0 + 0.0im
111 ₍₂₎   0.5 + 0.0im

Here, we measured the parity operator, as a result, the resulting state collapsed to the subspace with either even or odd parity.

source
YaoAPI.measureFunction
measure([, operator], register[, locs]; nshots=1, rng=Random.GLOBAL_RNG) -> Vector{Int}

Measure a quantum state and return measurement results of qudits. This measurement function a cheating version of measure! that does not collapse the input state. It also does not need to recompute the quantum state for performing multiple shots measurement.

Arguments

  • operator::AbstractBlock is the operator to measure.
  • register::AbstractRegister is the quantum state.
  • locs is the qubits to performance the measurement. If locs is not provided, all current active qudits are measured (regarding to active qudits,

see focus! and relax!).

Keyword arguments

  • nshots::Int is the number of shots.
  • rng is the random number generator.

Examples

julia> reg = product_state(bit"110")
ArrayReg{2, ComplexF64, Array...}
    active qubits: 3/3
    nlevel: 2

julia> measure(reg; nshots=3)
3-element Vector{DitStr{2, 3, Int64}}:
 110 ₍₂₎
 110 ₍₂₎
 110 ₍₂₎

julia> measure(reg, (2,3); nshots=3)
3-element Vector{DitStr{2, 2, Int64}}:
 11 ₍₂₎
 11 ₍₂₎
 11 ₍₂₎

The following example switches to the X basis for measurement.

julia> reg = apply!(product_state(bit"100"), repeat(3, H, 1:3))
ArrayReg{2, ComplexF64, Array...}
    active qubits: 3/3
    nlevel: 2

julia> measure(repeat(3, X, 1:3), reg; nshots=3)
3-element Vector{ComplexF64}:
 -1.0 + 0.0im
 -1.0 + 0.0im
 -1.0 + 0.0im

julia> reg = apply!(product_state(bit"101"), repeat(3, H, 1:3))
ArrayReg{2, ComplexF64, Array...}
    active qubits: 3/3
    nlevel: 2

julia> measure(repeat(3, X, 1:3), reg; nshots=3)
3-element Vector{ComplexF64}:
 1.0 - 0.0im
 1.0 - 0.0im
 1.0 - 0.0im
source
YaoAPI.select!Function
select!(dest::AbstractRegister, src::AbstractRegister, bits::Integer...) -> AbstractRegister
select!(register::AbstractRegister, bits::Integer...) -> register
select!(b::Integer) -> f(register)

select a subspace of given quantum state based on input eigen state bits. See also select for the non-inplace version. If the register is not provided, it returns a lambda expression that takes a register as the input.

Examples

julia> reg = ghz_state(3)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 3/3
    nlevel: 2

julia> select!(reg, bit"111")
ArrayReg{2, ComplexF64, Array...}
    active qubits: 0/0
    nlevel: 2

julia> norm(reg)
0.7071067811865476

The selection only works on the activated qubits, for example

julia> reg = focus!(ghz_state(3), (1, 2))
ArrayReg{2, ComplexF64, Array...}
    active qubits: 2/3
    nlevel: 2

julia> select!(reg, bit"11")
ArrayReg{2, ComplexF64, Array...}
    active qubits: 0/1
    nlevel: 2

julia> statevec(reg)
1×2 Matrix{ComplexF64}:
 0.0+0.0im  0.707107+0.0im
Tip

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 qudits.

source
YaoAPI.collapseto!Function
collapseto!(register, config)

Set the register to bit string literal bit_str (or an equivalent integer). About bit string literal, see more in @bit_str. This interface is only for emulation.

Examples

The following code collapse a random state to a certain state.

julia> measure(collapseto!(rand_state(3), bit"001"); nshots=3)
3-element Vector{DitStr{2, 3, Int64}}:
 001 ₍₂₎
 001 ₍₂₎
 001 ₍₂₎
source
YaoAPI.probsFunction
probs(register) -> Vector

Returns the probability distribution of computation basis, aka $|<x|ψ>|^2$.

Examples

julia> reg = product_state(bit"101");

julia> reg |> probs
8-element Vector{Float64}:
 0.0
 0.0
 0.0
 0.0
 0.0
 1.0
 0.0
 0.0
source
Missing docstring.

Missing docstring for most_probable,. Check Documenter's build log for details.

Density matrices

YaoAPI.DensityMatrixType
DensityMatrix{D,T,MT<:AbstractMatrix{T}} <: AbstractRegister{D}
DensityMatrix{D}(state::AbstractMatrix)
DensityMatrix(state::AbstractMatrix; nlevel=2)

Density matrix type, where state is a matrix. Type parameter D is the number of levels, it can also be specified by a keyword argument nlevel.

source
YaoAPI.density_matrixFunction
density_matrix(register_or_rho[, locations])

Returns the reduced density matrix for qubits at locations (default: all qubits).

Examples

The following code gets the single site reduce density matrix for the GHZ state.

julia> reg = ghz_state(3)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 3/3
    nlevel: 2

julia> density_matrix(reg, (2,)).state
2×2 Matrix{ComplexF64}:
 0.5+0.0im  0.0+0.0im
 0.0-0.0im  0.5+0.0im
source
YaoArrayRegister.rand_density_matrixFunction
rand_density_matrix([T=ComplexF64], n::Int; nlevel::Int=2, pure::Bool=false)

Generate a random density matrix by partial tracing half of the pure state.

Note

The generated density matrix is not strict hermitian due to rounding error. If you need to check hermicity, do not use ishermitian consider using isapprox(dm.state, dm.state') or explicit mark it as Hermitian.

source
YaoAPI.partial_trFunction
partial_tr(ρ, locs) -> DensityMatrix

Return a density matrix which is the partial traced on locs.

source
YaoAPI.purifyFunction
purify(r::DensityMatrix; nbit_env::Int=nactive(r)) -> ArrayReg

Get a purification of target density matrix.

Examples

The following example shows how to measure a local operator on the register, reduced density matrix and the purified register. Their results should be consistent.

julia> reg = ghz_state(3)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 3/3
    nlevel: 2

julia> r = density_matrix(reg, (2,));

julia> preg = purify(r)
ArrayReg{2, ComplexF64, Array...}
    active qubits: 1/2
    nlevel: 2

julia> isapprox(expect(Z + Y, preg), 0.0; atol=1e-10)
true

julia> isapprox(expect(Z + Y, r), 0.0; atol=1e-10)
true

julia> isapprox(expect(put(3, 2=>(Z + Y)), reg), 0.0; atol=1e-10)
true
source
Missing docstring.

Missing docstring for von_neumann_entropy, mutual_information,. Check Documenter's build log for details.