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.

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

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
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
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
YaoArrayRegister.onetoFunction
oneto(r::ArrayReg, n::Int=nqubits(r))

Returns an ArrayReg with 1:n qubits activated.

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

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

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
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)
repeat(x::AbstractBlock, locs)

Lazy curried version of repeat.

repeat(r::AbstractRegister, n::Int) -> register

Repeat register r for n times on batch dimension.

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.

state(ρ::DensityMatrix)

Return the raw state of density matrix ρ.

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.

YaoArrayRegister.relaxedvecFunction
relaxedvec(r::ArrayReg) -> AbstractArray

Return a matrix (vector) for B>1 (B=1) as a vector representation of state, with all qubits activated. See also state, statevec.

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

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

hypercubic(A::Array) -> Array

get the hypercubic representation for an array.

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.

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.

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.onetoMethod
oneto(n::Int) -> f(register)

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

YaoArrayRegister.onetoMethod
oneto(r::ArrayReg, n::Int=nqubits(r))

Returns an ArrayReg with 1:n qubits activated.

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

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

Get a purification of target density matrix.

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

YaoArrayRegister.relaxedvecMethod
relaxedvec(r::ArrayReg) -> AbstractArray

Return a matrix (vector) for B>1 (B=1) as a vector representation of state, with all qubits activated. See also state, statevec.

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.

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
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
YaoBase.probsMethod
probs(ρ)

Returns the probability distribution from a density matrix ρ.

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.

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
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])
YaoArrayRegister.matvecFunction
matvec(x::VecOrMat) -> MatOrVec

Return vector if a matrix is a column vector, else untouched.

YaoArrayRegister.sort_unitaryMethod
sort_unitary(U, locations::NTuple{N, Int}) -> U

Return an sorted unitary operator according to the locations.

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

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

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.