Array Registers

We provide ArrayReg as built in register type for simulations. It is a simple wrapper of a Julia array, e.g on CPU, we use Array by default and on CUDA devices we could use CuArray. You don't have to define your custom array type if the storage is array based.

Constructors

YaoArrayRegister.ArrayRegType
ArrayReg{B, T, MT <: AbstractMatrix{T}} <: AbstractRegister{B}

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

source

We define some shortcuts to create simulated quantum states easier:

YaoArrayRegister.product_stateFunction
product_state([T=ComplexF64], bit_str; nbatch=1)

Create an ArrayReg with bit string literal defined with @bit_str. See also zero_state, rand_state, uniform_state.

Examples

julia> product_state(bit"100"; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 3/3

julia> product_state(ComplexF32, bit"101"; nbatch=2)
ArrayReg{2, Complex{Float32}, Array...}
    active qubits: 3/3
source
product_state([T=ComplexF64], total::Int, bit_config::Integer; nbatch=1, no_transpose_storage=false)

Create an ArrayReg with bit configuration bit_config, total number of bits total. See also zero_state, rand_state, uniform_state.

Examples

julia> product_state(4, 3; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4

julia> product_state(4, 0b1001; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4

julia> product_state(ComplexF32, 4, 0b101)
ArrayReg{1, Complex{Float32}, Array...}
    active qubits: 4/4
Warning

This interface will not check whether the number of required digits for the bit configuration matches the total number of bits.

source
YaoArrayRegister.zero_stateFunction
zero_state([T=ComplexF64], n::Int; nbatch::Int=1)

Create an ArrayReg with total number of bits n. See also product_state, rand_state, uniform_state.

Examples

julia> zero_state(4)
ArrayReg{1, Complex{Float64}, Array...}
    active qubits: 4/4

julia> zero_state(ComplexF32, 4)
ArrayReg{1, Complex{Float32}, Array...}
    active qubits: 4/4

julia> zero_state(ComplexF32, 4; nbatch=3)
ArrayReg{3, Complex{Float32}, Array...}
    active qubits: 4/4
source
YaoArrayRegister.rand_stateFunction
rand_state([T=ComplexF64], n::Int; nbatch=1, no_transpose_storage=false)

Create a random ArrayReg with total number of qubits n.

Examples

julia> rand_state(4)
ArrayReg{1, Complex{Float64}, Array...}
    active qubits: 4/4

julia> rand_state(ComplexF64, 4)
ArrayReg{1, Complex{Float64}, Array...}
    active qubits: 4/4

julia> rand_state(ComplexF64, 4; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4
source
YaoArrayRegister.uniform_stateFunction
uniform_state([T=ComplexF64], n; nbatch=1, no_transpose_storage=false)

Create a uniform state: $\frac{1}{2^n} \sum_k |k⟩$. This state can also be created by applying H (Hadmard gate) on $|00⋯00⟩$ state.

Example

julia> uniform_state(4; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4

julia> uniform_state(ComplexF32, 4; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4
source
YaoArrayRegister.onetoFunction
oneto(r::ArrayReg, n::Int=nqubits(r))

Returns an ArrayReg with 1:n qubits activated.

source
oneto(n::Int) -> f(register)

Like oneto(register, n), but the input register is delayed.

source
Base.repeatFunction
repeat(register, n)

Create an ArrayReg by copying the original register for n times on batch dimension.

Example

julia> repeat(ArrayReg{3}(bit"101"), 4)
ArrayReg{12, Complex{Float64}, Array...}
    active qubits: 3/3
source
repeat(r::AbstractRegister, n::Int) -> register

Repeat register r for n times on batch dimension.

source
repeat(n, x::AbstractBlock[, locs]) -> RepeatedBlock{n}

Create a RepeatedBlock with total number of qubits n and the block to repeat on given location or on all the locations.

Example

This will create a repeat block which puts 4 X gates on each location.

julia> repeat(4, X)
nqubits: 4
repeat on (1, 2, 3, 4)
└─ X

You can also specify the location

julia> repeat(4, X, (1, 2))
nqubits: 4
repeat on (1, 2)
└─ X

But repeat won't copy the gate, thus, if it is a gate with parameter, e.g a phase(0.1), the parameter will change simultaneously.

julia> g = repeat(4, phase(0.1))
nqubits: 4
repeat on (1, 2, 3, 4)
└─ phase(0.1)

julia> g.content
phase(0.1)

julia> g.content.theta = 0.2
0.2

julia> g
nqubits: 4
repeat on (1, 2, 3, 4)
└─ phase(0.2)
source
repeat(x::AbstractBlock, locs)

Lazy curried version of repeat.

source

Properties

You can access the storage of an ArrayReg with:

YaoArrayRegister.stateFunction
state(register::ArrayReg) -> raw array

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

source
state(ρ::DensityMatrix)

Return the raw state of density matrix ρ.

source
YaoArrayRegister.statevecFunction
statevec(r::ArrayReg) -> array

Return a state matrix/vector by droping the last dimension of size 1. See also state.

Warning

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

source
BitBasis.hypercubicFunction
hypercubic(r::ArrayReg) -> AbstractArray

Return the hypercubic form (high dimensional tensor) of this register, only active qubits are considered. See also rank3.

source
hypercubic(A::Array) -> Array

get the hypercubic representation for an array.

source
YaoArrayRegister.rank3Function
rank3(r::ArrayReg)

Return the rank 3 tensor representation of state, the 3 dimensions are (activated space, remaining space, batch dimension). See also rank3.

source

Operations

We defined basic arithmatics for ArrayReg, besides since we do not garantee normalization for some operations on ArrayReg for simulation, normalize! and isnormalized is provided to check and normalize the simulated register.

Specialized Instructions

We define some specialized instruction by specializing instruct! to improve the performance for simulation and dispatch them with multiple dispatch.

Implemented instruct! is listed below:

Measurement

Simulation of measurement is mainly achieved by sampling and projection.

Sample

Suppose we want to measure operational subspace, we can first get

\[p(x) = \|\langle x|\psi\rangle\|^2 = \sum\limits_{y} \|L(x, y, .)\|^2.\]

Then we sample an $a\sim p(x)$. If we just sample and don't really measure (change wave function), its over.

Projection

\[|\psi\rangle' = \sum_y L(a, y, .)/\sqrt{p(a)} |a\rangle |y\rangle\]

Good! then we can just remove the operational qubit space since x and y spaces are totally decoupled and x is known as in state a, then we get

\[|\psi\rangle'_r = \sum_y l(0, y, .) |y\rangle\]

where l = L(a:a, :, :)/sqrt(p(a)).

Others

BitBasis.hypercubicMethod
hypercubic(r::ArrayReg) -> AbstractArray

Return the hypercubic form (high dimensional tensor) of this register, only active qubits are considered. See also rank3.

source
YaoArrayRegister.datatypeMethod
datatype(register) -> Int

Returns the numerical data type used by register.

Note

datatype is not the same with eltype, since AbstractRegister family is not exactly the same with AbstractArray, it is an iterator of several registers.

source
YaoArrayRegister.product_stateMethod
product_state([T=ComplexF64], bit_str; nbatch=1)

Create an ArrayReg with bit string literal defined with @bit_str. See also zero_state, rand_state, uniform_state.

Examples

julia> product_state(bit"100"; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 3/3

julia> product_state(ComplexF32, bit"101"; nbatch=2)
ArrayReg{2, Complex{Float32}, Array...}
    active qubits: 3/3
source
YaoArrayRegister.product_stateMethod
product_state([T=ComplexF64], total::Int, bit_config::Integer; nbatch=1, no_transpose_storage=false)

Create an ArrayReg with bit configuration bit_config, total number of bits total. See also zero_state, rand_state, uniform_state.

Examples

julia> product_state(4, 3; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4

julia> product_state(4, 0b1001; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4

julia> product_state(ComplexF32, 4, 0b101)
ArrayReg{1, Complex{Float32}, Array...}
    active qubits: 4/4
Warning

This interface will not check whether the number of required digits for the bit configuration matches the total number of bits.

source
YaoArrayRegister.purifyMethod
purify(r::DensityMatrix{B}; nbit_env::Int=nactive(r)) -> ArrayReg

Get a purification of target density matrix.

source
YaoArrayRegister.rand_stateMethod
rand_state([T=ComplexF64], n::Int; nbatch=1, no_transpose_storage=false)

Create a random ArrayReg with total number of qubits n.

Examples

julia> rand_state(4)
ArrayReg{1, Complex{Float64}, Array...}
    active qubits: 4/4

julia> rand_state(ComplexF64, 4)
ArrayReg{1, Complex{Float64}, Array...}
    active qubits: 4/4

julia> rand_state(ComplexF64, 4; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4
source
YaoArrayRegister.rank3Method
rank3(r::ArrayReg)

Return the rank 3 tensor representation of state, the 3 dimensions are (activated space, remaining space, batch dimension). See also rank3.

source
YaoArrayRegister.statevecMethod
statevec(r::ArrayReg) -> array

Return a state matrix/vector by droping the last dimension of size 1. See also state.

Warning

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

source
YaoArrayRegister.uniform_stateMethod
uniform_state([T=ComplexF64], n; nbatch=1, no_transpose_storage=false)

Create a uniform state: $\frac{1}{2^n} \sum_k |k⟩$. This state can also be created by applying H (Hadmard gate) on $|00⋯00⟩$ state.

Example

julia> uniform_state(4; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4

julia> uniform_state(ComplexF32, 4; nbatch=2)
ArrayReg{2, Complex{Float64}, Array...}
    active qubits: 4/4
source
YaoArrayRegister.zero_stateMethod
zero_state([T=ComplexF64], n::Int; nbatch::Int=1)

Create an ArrayReg with total number of bits n. See also product_state, rand_state, uniform_state.

Examples

julia> zero_state(4)
ArrayReg{1, Complex{Float64}, Array...}
    active qubits: 4/4

julia> zero_state(ComplexF32, 4)
ArrayReg{1, Complex{Float32}, Array...}
    active qubits: 4/4

julia> zero_state(ComplexF32, 4; nbatch=3)
ArrayReg{3, Complex{Float32}, Array...}
    active qubits: 4/4
source
YaoBase.fidelityMethod
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.

fidelity'(pair_or_reg1, pair_or_reg2) -> (g1, g2)

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.

source
YaoBase.probsMethod
probs(ρ)

Returns the probability distribution from a density matrix ρ.

source
Base.joinMethod
join(regs...)

concat a list of registers regs to a larger register, each register should have the same batch size. See also repeat.

source
Base.repeatMethod
repeat(register, n)

Create an ArrayReg by copying the original register for n times on batch dimension.

Example

julia> repeat(ArrayReg{3}(bit"101"), 4)
ArrayReg{12, Complex{Float64}, Array...}
    active qubits: 3/3
source
YaoArrayRegister.contiguous_shape_ordersMethod
contiguous_shape_orders(shape, orders)

Merge the shape and orders if the orders are contiguous. Returns the new merged shape and order.

Example

julia> YaoArrayRegister.contiguous_shape_orders((2, 3, 4), (1, 2, 3))
([24], [1])
source
YaoArrayRegister.swapcols!Function
swapcols!(v::VecOrMat, i::Int, j::Int[, f1, f2]) -> VecOrMat

swap col i and col j of v inplace, with f1, f2 factors applied on i and j (before swap).

source
YaoArrayRegister.swaprows!Function
swaprows!(v::VecOrMat, i::Int, j::Int[, f1, f2]) -> VecOrMat

swap row i and row j of v inplace, with f1, f2 factors applied on i and j (before swap).

source
YaoArrayRegister.u1rows!Function
u1rows!(state::VecOrMat, i::Int, j::Int, a, b, c, d) -> VecOrMat

apply u1 on row i and row j of state inplace.

source