# Blocks

**Blocks** are the basic building blocks of a quantum circuit in Yao. It simply means a quantum operator, thus, all the blocks have matrices in principal and one can get its matrix by `mat`

. The basic blocks required to build an arbitrary quantum circuit is defined in the component package `YaoBlocks`

.

Block Tree serves as an intermediate representation for Yao to analysis, optimize the circuit, then it will be lowered to instructions like for simulations, blocks will be lowered to `instruct!`

calls.

The structure of blocks is the same with a small type system, it consists of two basic kinds of blocks: `CompositeBlock`

(like composite types), and `PrimitiveBlock`

(like primitive types). By combining these two kinds of blocks together, we'll be able to construct a quantum circuit and represent it in a tree data structure.

## Primitive Blocks

Primitive blocks are subtypes of `PrimitiveBlock`

, they are the leaf nodes in a block tree, thus primitive types do not have subtypes.

We provide the following primitive blocks:

`YaoBlocks.GeneralMatrixBlock`

— Type`GeneralMatrixBlock{M, N, MT} <: PrimitiveBlock{N}`

General matrix gate wraps a matrix operator to quantum gates. This is the most general form of a quantum gate. `M`

is the hilbert dimension (first dimension), `N`

is the hilbert dimension (second dimension) of current quantum state. For most quantum gates, we have $M = N$.

`YaoBlocks.IdentityGate`

— Type`IdentityGate{N} <: TrivialGate{N}`

The identity gate.

`YaoBlocks.Measure`

— Type```
Measure{N, K, OT, LT, PT, RNG} <: PrimitiveBlock{N}
Measure(n::Int; rng=Random.GLOBAL_RNG, operator=ComputationalBasis(), locs=1:n, resetto=nothing, remove=false)
```

Measure operator.

`YaoBlocks.Measure`

— Method`Measure(n::Int; rng=Random.GLOBAL_RNG, operator=ComputationalBasis(), locs=AllLocs(), resetto=nothing, remove=false)`

Create a `Measure`

block with number of qubits `n`

.

**Example**

You can create a `Measure`

block on given basis (default is the computational basis).

```
julia> Measure(4)
Measure(4;postprocess=NoPostProcess())
```

Or you could specify which qubits you are going to measure

```
julia> Measure(4; locs=1:3)
Measure(4;locs=(1, 2, 3), postprocess=NoPostProcess())
```

by default this will collapse the current register to measure results.

```
julia> r = normalize!(ArrayReg(bit"000") + ArrayReg(bit"111"))
ArrayReg{1, Complex{Float64}, Array...}
active qubits: 3/3
julia> state(r)
8×1 Array{Complex{Float64},2}:
0.7071067811865475 + 0.0im
0.0 + 0.0im
0.0 + 0.0im
0.0 + 0.0im
0.0 + 0.0im
0.0 + 0.0im
0.0 + 0.0im
0.7071067811865475 + 0.0im
julia> r |> Measure(3)
Measure(3;postprocess=NoPostProcess())
julia> state(r)
1×1 Array{Complex{Float64},2}:
1.0 + 0.0im
```

But you can also specify the target bit configuration you want to collapse to with keyword `resetto`

.

```jldoctest; setup=:(using YaoBlocks; using BitBasis) julia> m = Measure(4; resetto=bit"0101") Measure(4;postprocess=ResetTo{BitStr{4,Int64}}(0101 ₍₂₎))

julia> m.postprocess ResetTo{BitStr{4,Int64}}(0101 ₍₂₎)```

`YaoBlocks.PhaseGate`

— Type`PhiGate`

Global phase gate.

`YaoBlocks.PrimitiveBlock`

— Type`PrimitiveBlock{N} <: AbstractBlock{N}`

Abstract type that all primitive block will subtype from. A primitive block is a concrete block who can not be decomposed into other blocks. All composite block can be decomposed into several primitive blocks.

subtype for primitive block with parameter should implement `hash`

and `==`

method to enable key value cache.

`YaoBlocks.RotationGate`

— Type`RotationGate{N, T, GT <: AbstractBlock{N, Complex{T}}} <: PrimitiveBlock{N, Complex{T}}`

RotationGate, with GT both hermitian and isreflexive.

**Definition**

`YaoBlocks.ShiftGate`

— Type`ShiftGate <: PrimitiveBlock`

Phase shift gate.

**Definition**

`YaoBlocks.TimeEvolution`

— Type`TimeEvolution{N, TT, GT} <: PrimitiveBlock{N}`

TimeEvolution, where GT is block type. input matrix should be hermitian.

!!!note: `TimeEvolution`

contructor check hermicity of the input block by default, but sometimes it can be slow. Turn off the check manually by specifying optional parameter `check_hermicity = false`

.

## Composite Blocks

Composite blocks are subtypes of `CompositeBlock`

, they are the composition of blocks.

We provide the following composite blocks:

`YaoBlocks.AbstractContainer`

— Type`AbstractContainer{BT, N} <: CompositeBlock{N}`

Abstract type for container block. Container blocks are blocks contain a single block. Container block should have a

`YaoBlocks.Add`

— Type```
Add{N} <: CompositeBlock{N}
Add{N}(iterable) -> Add
Add(blocks::AbstractBlock{N}...) -> Add
```

`YaoBlocks.CachedBlock`

— Type`CachedBlock{ST, BT, N} <: TagBlock{BT, N}`

A label type that tags an instance of type `BT`

. It forwards every methods of the block it contains, except `mat`

and `apply!`

, it will cache the matrix form whenever the program has.

`YaoBlocks.ChainBlock`

— Type`ChainBlock{N} <: CompositeBlock{N}`

`ChainBlock`

is a basic construct tool to create user defined blocks horizontically. It is a `Vector`

like composite type.

`YaoBlocks.CompositeBlock`

— Type`CompositeBlock{N} <: AbstractBlock{N}`

Abstract supertype which composite blocks will inherit from. Composite blocks are blocks composited from other `AbstractBlock`

s, thus it is a `AbstractBlock`

as well.

`YaoBlocks.Daggered`

— Type`Daggered{N, BT} <: TagBlock{N}`

Wrapper block allowing to execute the inverse of a block of quantum circuit.

`YaoBlocks.Daggered`

— Method`Daggered(x)`

Create a `Daggered`

block with given block `x`

.

**Example**

The inverse QFT is not hermitian, thus it will be tagged with a `Daggered`

block.

```
julia> A(i, j) = control(i, j=>shift(2π/(1<<(i-j+1))));
julia> B(n, i) = chain(n, i==j ? put(i=>H) : A(j, i) for j in i:n);
julia> qft(n) = chain(B(n, i) for i in 1:n);
julia> struct QFT{N} <: PrimitiveBlock{N} end
julia> QFT(n) = QFT{n}();
julia> circuit(::QFT{N}) where N = qft(N);
julia> YaoBlocks.mat(x::QFT) = mat(circuit(x));
julia> QFT(2)'
[†]QFT{2}
```

`YaoBlocks.KronBlock`

— Type`KronBlock{N, T, MT<:AbstractBlock} <: CompositeBlock{N, T}`

composite block that combine blocks by kronecker product.

`YaoBlocks.PutBlock`

— Type`PutBlock <: AbstractContainer`

Type for putting a block at given locations.

`YaoBlocks.RepeatedBlock`

— Type`RepeatedBlock <: AbstractContainer`

Repeat the same block on given locations.

`YaoBlocks.Scale`

— Type`Scale{S <: Union{Number, Val}, N, BT <: AbstractBlock{N}} <: TagBlock{BT, N}`

`Scale`

a block with scalar. it can be either a `Number`

or a compile time `Val`

.

**Example**

```
julia> 2 * X
[scale: 2] X
julia> im * Z
[+im] Z
julia> -im * Z
[-im] Z
julia> -Z
[-] Z
```

`YaoBlocks.Subroutine`

— Type`Subroutine{N, T, BT <: AbstractBlock} <: AbstractContainer{BT, N, T}`

Subroutine node on given locations. This allows you to shoehorn a smaller circuit to a larger one.

`YaoBlocks.TagBlock`

— Type`TagBlock{BT, N} <: AbstractContainer{BT, N}`

`TagBlock`

is a special kind of Container block, it forwards most of the methods but tag the block with some extra information.

`YaoBlocks.UnitaryChannel`

— Type`UnitaryChannel(operators[, weights])`

Create a unitary channel, optionally weighted from an list of weights. The unitary channel is defined as below in Kraus representation

Unitary channel will only normalize the weights when calculating the matrix form, thus you should be careful when you need this condition for other purpose.

when applying a `UnitaryChannel`

on the register, a unitary will be sampled uniformly or optionally from given weights, then this unitary will be applied to the register.

**Example**

```
julia> UnitaryChannel([X, Y, Z])
nqubits: 1
unitary_channel
├─ [1.0] X
├─ [1.0] Y
└─ [1.0] Z
```

Or with weights

```
julia> UnitaryChannel([X, Y, Z], [0.1, 0.2, 0.7])
nqubits: 1
unitary_channel
├─ [0.1] X
├─ [0.2] Y
└─ [0.7] Z
```

## APIs

`Base.kron`

— Method`kron(n, blocks::Pair{<:Any, <:AbstractBlock}...)`

Return a `KronBlock`

, with total number of qubits `n`

and pairs of blocks.

**Example**

Use `kron`

to construct a `KronBlock`

, it will put an `X`

gate on the `1`

st qubit, and a `Y`

gate on the `3`

rd qubit.

```
julia> kron(4, 1=>X, 3=>Y)
nqubits: 4
kron
├─ 1=>X
└─ 3=>Y
```

`Base.kron`

— Method```
kron(blocks::AbstractBlock...)
kron(n, itr)
```

Return a `KronBlock`

, with total number of qubits `n`

, and `blocks`

should use all the locations on `n`

wires in quantum circuits.

**Example**

You can use kronecker product to composite small blocks to a large blocks.

```
julia> kron(X, Y, Z, Z)
nqubits: 4
kron
├─ 1=>X
├─ 2=>Y
├─ 3=>Z
└─ 4=>Z
```

`Base.kron`

— Method```
kron(blocks...) -> f(n)
kron(itr) -> f(n)
```

Return a lambda, which will take the total number of qubits as input.

**Example**

If you don't know the number of qubit yet, or you are just too lazy, it is fine.

```
julia> kron(put(1=>X) for _ in 1:2)
(n -> kron(n, (n -> put(n, 1 => X)), (n -> put(n, 1 => X))))
julia> kron(X for _ in 1:2)
nqubits: 2
kron
├─ 1=>X
└─ 2=>X
julia> kron(1=>X, 3=>Y)
(n -> kron(n, 1 => X, 3 => Y))
```

`Base.repeat`

— Method`repeat(x::AbstractBlock, locs)`

Lazy curried version of `repeat`

.

`Base.repeat`

— Method`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)
```

`YaoBlocks.Rx`

— Method`YaoBlocks.Ry`

— Method`YaoBlocks.Rz`

— Method`YaoBlocks.applymatrix`

— Method`applymatrix(g::AbstractBlock) -> Matrix`

Transform the apply! function of specific block to dense matrix.

`YaoBlocks.cache`

— Function`cache(x[, level=1; recursive=false])`

Create a `CachedBlock`

with given block `x`

, which will cache the matrix of `x`

for the first time it calls `mat`

, and use the cached matrix in the following calculations.

**Example**

```
julia> cache(control(3, 1, 2=>X))
nqubits: 3
[cached] control(1)
└─ (2,) X
julia> chain(cache(control(3, 1, 2=>X)), repeat(H))
nqubits: 3
chain
├─ [cached] control(1)
│ └─ (2,) X
└─ repeat on (1, 2, 3)
└─ H
```

`YaoBlocks.cache_key`

— Method`cache_key(block)`

Returns the key that identify the matrix cache of this block. By default, we use the returns of `parameters`

as its key.

`YaoBlocks.cache_type`

— Method`cache_type(::Type) -> DataType`

Return the element type that a `CacheFragment`

will use.

`YaoBlocks.chain`

— Method`chain(n)`

Return an empty `ChainBlock`

which can be used like a list of blocks.

`YaoBlocks.chain`

— Method`chain()`

Return an lambda `n->chain(n)`

.

`YaoBlocks.chain`

— Method`chain(blocks...)`

Return a `ChainBlock`

which chains a list of blocks with same `nqubits`

. If there is lazy evaluated block in `blocks`

, chain can infer the number of qubits and create an instance itself.

`YaoBlocks.chcontent`

— Method`chcontent(x, blk)`

Create a similar block of `x`

and change its content to blk.

`YaoBlocks.chmeasureoperator`

— Method`chmeasureoperator(m::Measure, op::AbstractBlock)`

change the measuring `operator`

. It will also discard existing measuring results.

`YaoBlocks.chsubblocks`

— Method`chsubblocks(composite_block, itr)`

Change the sub-blocks of a `CompositeBlock`

with given iterator `itr`

.

`YaoBlocks.cnot`

— Method`cnot([n, ]ctrl_locs, location)`

Return a speical `ControlBlock`

, aka CNOT gate with number of active qubits `n`

and locs of control qubits `ctrl_locs`

, and `location`

of `X`

gate.

**Example**

```
julia> cnot(3, (2, 3), 1)
nqubits: 3
control(2, 3)
└─ (1,) X
julia> cnot(2, 1)
(n -> cnot(n, 2, 1))
```

`YaoBlocks.collect_blocks`

— Method`collect_blocks(block_type, root)`

Return a `ChainBlock`

with all block of `block_type`

in root.

`YaoBlocks.content`

— Method`content(x)`

Returns the content of `x`

.

`YaoBlocks.control`

— Method`control(ctrl_locs, target) -> f(n)`

Return a lambda that takes the number of total active qubits as input. See also `control`

.

**Example**

```
julia> control((2, 3), 1=>X)
(n -> control(n, (2, 3), 1 => X))
julia> control(2, 1=>X)
(n -> control(n, 2, 1 => X))
```

`YaoBlocks.control`

— Method`control(n, ctrl_locs, target)`

Return a `ControlBlock`

with number of active qubits `n`

and control locs `ctrl_locs`

, and control target in `Pair`

.

**Example**

```
julia> control(4, (1, 2), 3=>X)
nqubits: 4
control(1, 2)
└─ (3,) X
julia> control(4, 1, 3=>X)
nqubits: 4
control(1)
└─ (3,) X
```

`YaoBlocks.control`

— Method`control(target) -> f(ctrl_locs)`

Return a lambda that takes a `Tuple`

of control qubits locs as input. See also `control`

.

**Example**

```
julia> control(1=>X)
(ctrl_locs -> control(ctrl_locs, 1 => X))
julia> control((2, 3) => YaoBlocks.ConstGate.CNOT)
(ctrl_locs -> control(ctrl_locs, (2, 3) => CNOT))
```

`YaoBlocks.control`

— Method`control(ctrl_locs::Int...) -> f(target)`

Return a lambda that takes a `Pair`

of control target as input. See also `control`

.

**Example**

```
julia> control(1, 2)
(target -> control((1, 2), target))
```

`YaoBlocks.cz`

— Method`cz([n, ]ctrl_locs, location)`

Return a speical `ControlBlock`

, aka CZ gate with number of active qubits `n`

and locs of control qubits `ctrl_locs`

, and `location`

of `Z`

gate. See also `cnot`

.

`YaoBlocks.dispatch!`

— Method`dispatch!(x::AbstractBlock, collection)`

Dispatch parameters in collection to block tree `x`

.

it will try to dispatch the parameters in collection first.

`YaoBlocks.dump_gate`

— Function`dump_gate(blk::AbstractBlock) -> Expr`

convert a gate to a YaoScript expression for serization. The fallback is `GateTypeName(fields...)`

`YaoBlocks.expect`

— Method```
expect(op::AbstractBlock, reg) -> Vector
expect(op::AbstractBlock, reg => circuit) -> Vector
expect(op::AbstractBlock, density_matrix) -> Vector
```

Get the expectation value of an operator, the second parameter can be a register `reg`

or a pair of input register and circuit `reg => circuit`

.

expect'(op::AbstractBlock, reg=>circuit) -> Pair expect'(op::AbstractBlock, reg) -> AbstracRegister

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

, with `gψ`

the gradient of input state and `gparams`

the gradients of circuit parameters. For register input, the return value is a register.

For batched register, `expect(op, reg=>circuit)`

returns a vector of size number of batch as output. However, one can not differentiate over a vector loss, so `expect'(op, reg=>circuit)`

accumulates the gradient over batch, rather than returning a batched gradient of parameters.

`YaoBlocks.getiparams`

— Method`getiparams(block)`

Returns the intrinsic parameters of node `block`

, default is an empty tuple.

`YaoBlocks.igate`

— Method`igate(n::Int)`

The constructor for identity gate.

`YaoBlocks.iparams_eltype`

— Method`iparams_eltype(block)`

Return the element type of `getiparams`

.

`YaoBlocks.map_address`

— Function`map_address(block::AbstractBlock, info::AddressInfo) -> AbstractBlock`

map the locations in `block`

to target locations.

**Example**

`map_address`

can be used to embed a sub-circuit to a larger one.

```
julia> c = chain(5, repeat(H, 1:5), put(2=>X), kron(1=>X, 3=>Y))
nqubits: 5
chain
├─ repeat on (1, 2, 3, 4, 5)
│ └─ H
├─ put on (2)
│ └─ X
└─ kron
├─ 1=>X
└─ 3=>Y
julia> map_address(c, AddressInfo(10, [6,7,8,9,10]))
nqubits: 10
chain
├─ repeat on (6, 7, 8, 9, 10)
│ └─ H
├─ put on (7)
│ └─ X
└─ kron
├─ 6=>X
└─ 8=>Y
```

`YaoBlocks.mat`

— Method`mat([T=ComplexF64], blk)`

Returns the matrix form of given block.

`YaoBlocks.mat`

— Method`mat(A::GeneralMatrixBlock)`

Return the matrix of general matrix block.

!!!warn

```
Instead of converting it to the default data type `ComplexF64`,
this will return its contained matrix.
```

`YaoBlocks.matblock`

— Method`matblock(m::AbstractMatrix)`

Create a `GeneralMatrixBlock`

with a matrix `m`

.

**Example**

```
julia> matblock(ComplexF64[0 1;1 0])
matblock(...)
```

!!!warn

```
Instead of converting it to the default data type `ComplexF64`,
this will return its contained matrix when calling `mat`.
```

`YaoBlocks.matblock`

— Method`matblock(m::AbstractMatrix)`

Create a `GeneralMatrixBlock`

with a matrix `m`

.

`YaoBlocks.niparams`

— Method`nparameters(block) -> Int`

Return number of parameters in `block`

. See also `nparameters`

.

`YaoBlocks.occupied_locs`

— Method`occupied_locs(x)`

Return a tuple of occupied locations of `x`

.

`YaoBlocks.operator_fidelity`

— Method`operator_fidelity(b1::AbstractBlock, b2::AbstractBlock) -> Number`

Operator fidelity defined as

Here, `d`

is the size of the Hilbert space. Note this quantity is independant to global phase. See arXiv: 0803.2940v2, Equation (2) for reference.

`YaoBlocks.parameters!`

— Method`parameters!(out, block)`

Append all the parameters contained in block tree with given root `block`

to `out`

.

`YaoBlocks.parameters`

— Method`parameters(block)`

Returns all the parameters contained in block tree with given root `block`

.

`YaoBlocks.parameters_eltype`

— Method`parameters_eltype(x)`

Return the element type of `parameters`

.

`YaoBlocks.phase`

— Method`phase(theta)`

Returns a global phase gate. Defined with following matrix form:

**Example**

You can create a global phase gate with a phase (a real number).

```
julia> phase(0.1)
phase(0.1)
```

`YaoBlocks.popdispatch!`

— Method`popdispatch!(block, list)`

Pop the first `nparameters`

parameters of list, then dispatch them to the block tree `block`

. See also `dispatch!`

.

`YaoBlocks.popdispatch!`

— Method`popdispatch!(f, block, list)`

Pop the first `nparameters`

parameters of list, map them with a function `f`

, then dispatch them to the block tree `block`

. See also `dispatch!`

.

`YaoBlocks.postwalk`

— Method`postwalk(f, src::AbstractBlock)`

Walk the tree and call `f`

after the children are visited.

`YaoBlocks.prewalk`

— Method`prewalk(f, src::AbstractBlock)`

Walk the tree and call `f`

once the node is visited.

`YaoBlocks.print_annotation`

— Method`print_annotation(io, root, node, child, k)`

Print the annotation of `k`

-th `child`

of node, aka the `k`

-th element of `subblocks(node)`

.

`YaoBlocks.print_prefix`

— Method`print_prefix(io, depth, charset, active_levels)`

print prefix of a tree node in a single line.

`YaoBlocks.print_title`

— Method`print_title(io, block)`

Print the title of given `block`

of an `AbstractBlock`

.

`YaoBlocks.print_tree`

— Function`print_tree(io, root, node[, depth=1, active_levels=()]; kwargs...)`

Print the block tree.

**Keywords**

`maxdepth`

: max tree depth to print`charset`

: default is ('├','└','│','─'). See also`BlockTreeCharSet`

.`title`

: control whether to print the title,`true`

or`false`

, default is`true`

`YaoBlocks.print_tree`

— Method`print_tree([io=stdout], root)`

Print the block tree.

`YaoBlocks.projector`

— Method`projector(x)`

Return projector on `0`

or projector on `1`

.

`YaoBlocks.pswap`

— Method```
pswap(n::Int, i::Int, j::Int, α::Real)
pswap(i::Int, j::Int, α::Real) -> f(n)
```

parametrized swap gate.

`YaoBlocks.put`

— Method`YaoBlocks.put`

— Method`put(total::Int, pair)`

Create a `PutBlock`

with total number of active qubits, and a pair of location and block to put on.

**Example**

```
julia> put(4, 1=>X)
nqubits: 4
put on (1)
└─ X
```

If you want to put a multi-qubit gate on specific locations, you need to write down all possible locations.

```
julia> put(4, (1, 3)=>kron(X, Y))
nqubits: 4
put on (1, 3)
└─ kron
├─ 1=>X
└─ 2=>Y
```

The outter locations creates a scope which make it seems to be a contiguous two qubits for the block inside `PutBlock`

.

It is better to use `subroutine`

instead of `put`

for large blocks, since put will use the matrix of its contents directly instead of making use of what's in it. `put`

is more efficient for small blocks.

`YaoBlocks.rot`

— Method`rot(U, theta)`

Return a `RotationGate`

on U axis.

`YaoBlocks.setiparams!`

— Method```
setiparams!(block, itr)
setiparams!(block, params...)
```

Set the parameters of `block`

.

`YaoBlocks.setiparams!`

— Method`setiparams(f, block, collection)`

Set parameters of `block`

to the value in `collection`

mapped by `f`

.

`YaoBlocks.setiparams!`

— Method`setiparams(f, block, symbol)`

Set the parameters to a given symbol, which can be :zero, :random.

`YaoBlocks.shift`

— Method`YaoBlocks.subblocks`

— Method`subblocks(x)`

Returns an iterator of the sub-blocks of a composite block. Default is empty.

`YaoBlocks.subroutine`

— Method`subroutine(block, locs) -> f(n)`

Lazy curried version of `subroutine`

.

`YaoBlocks.subroutine`

— Method`subroutine(n, block, locs)`

Create a `Subroutine`

block with total number of current active qubits `n`

, which concentrates given wire location together to `length(locs)`

active qubits, and relax the concentration afterwards.

**Example**

Subroutine is equivalent to `put`

a block on given position mathematically, but more efficient and convenient for large blocks.

```
julia> r = rand_state(3)
ArrayReg{1, Complex{Float64}, Array...}
active qubits: 3/3
julia> apply!(copy(r), subroutine(X, 1)) ≈ apply!(copy(r), put(1=>X))
true
```

It works for in-contigious locs as well

```
julia> r = rand_state(4)
ArrayReg{1, Complex{Float64}, Array...}
active qubits: 4/4
julia> cc = subroutine(4, kron(X, Y), (1, 3))
nqubits: 4
Subroutine: (1, 3)
└─ kron
├─ 1=>X
└─ 2=>Y
julia> pp = chain(4, put(1=>X), put(3=>Y))
nqubits: 4
chain
├─ put on (1)
│ └─ X
└─ put on (3)
└─ Y
julia> apply!(copy(r), cc) ≈ apply!(copy(r), pp)
true
```

`YaoBlocks.swap`

— Method`swap(n, loc1, loc2)`

Create a `n`

-qubit `Swap`

gate which swap `loc1`

and `loc2`

.

**Example**

```
julia> swap(4, 1, 2)
nqubits: 4
put on (1, 2)
└─ SWAP
```

`YaoBlocks.swap`

— Method`swap(loc1, loc2) -> f(n)`

Create a lambda that takes the total number of active qubits as input. Lazy curried version of `swap(n, loc1, loc2)`

. See also `Swap`

.

**Example**

```
julia> swap(1, 2)
(n -> swap(n, 1, 2))
```

`YaoBlocks.time_evolve`

— Method`TimeEvolution(H, dt[; tol::Real=1e-7])`

Create a `TimeEvolution`

block with Hamiltonian `H`

and time step `dt`

. The `TimeEvolution`

block will use Krylove based `expv`

to calculate time propagation.

Optional keywords are tolerance `tol`

(default is `1e-7`

) `TimeEvolution`

block can also be used for imaginary time evolution if dt is complex.

`YaoBlocks.@yao_str`

— Macro```
@yao_str
yao"..."
```

The mark up language for quantum circuit.

`Base.:|>`

— Method`|>(register, blk)`

Pipe operator for quantum circuits.

**Example**

`julia> ArrayReg(bit"0") |> X |> Y`

`|>`

is equivalent to `apply!`

, which means it has side effects. You need to copy original register, if you do not want to change it in-place.

`YaoBlocks.cunmat`

— Function`cunmat(nbit::Int, cbits::NTuple{C, Int}, cvals::NTuple{C, Int}, U0::AbstractMatrix, locs::NTuple{M, Int}) where {C, M} -> AbstractMatrix`

control-unitary matrix

`YaoBlocks.decode_sign`

— Method`decode_sign(ctrls...)`

Decode signs into control sequence on control or inversed control.

`YaoBlocks.eigenbasis`

— Method`eigenbasis(op::AbstractBlock{N})`

Return the `eigenvalue`

and `eigenvectors`

of target operator. By applying `eigenvector`

' to target state, one can swith the basis to the eigenbasis of this operator. However, `eigenvalues`

does not have a specific form.

`YaoBlocks.gate_expr`

— Method`gate_expr(::Val{G}, args, info)`

Obtain the gate constructior from its YaoScript expression. `G`

is a symbol for the gate type, the default constructor is `G(args...)`

. `info`

contains the informations about the number of qubit and Yao version.

`YaoBlocks.getcol`

— Method`getcol(csc::SDparseMatrixCSC, icol::Int) -> (View, View)`

get specific col of a CSC matrix, returns a slice of (rowval, nzval)

`YaoBlocks.num_nonzero`

— Function`num_nonzero(nbits, nctrls, U)`

Return number of nonzero entries of the matrix form of control-U gate. `nbits`

is the number of qubits, and `nctrls`

is the number of control qubits.

`YaoBlocks.parse_block`

— Function`parse_block(n, ex)`

This function parse the julia object `ex`

to a quantum block, it defines the syntax of high level interfaces. `ex`

can be a function takes number of qubits `n`

as input or it can be a pair.

`YaoBlocks.print_subtypetree`

— Function`print_subtypetree(::Type[, level=1, indent=4])`

Print subtype tree, `level`

specify the depth of the tree.

`YaoBlocks.rmlines`

— Method`rmlines(ex)`

Remove `LineNumberNode`

from an `Expr`

.

`YaoBlocks.setcol!`

— Method`setcol!(csc::SparseMatrixCSC, icol::Int, rowval::AbstractVector, nzval) -> SparseMatrixCSC`

set specific col of a CSC matrix

`YaoBlocks.simple_commute_eachother`

— MethodReturn true if operators commute to each other.

`YaoBlocks.u1ij!`

— Function`u1ij!(target, i, j, a, b, c, d)`

single u1 matrix into a target matrix.

For coo, we take an additional parameter * ptr: starting position to store new data.

`YaoBlocks.unmat`

— Method`unmat(nbit::Int, U::AbstractMatrix, locs::NTuple) -> AbstractMatrix`

Return the matrix representation of putting matrix at locs.