Binary Basics

Binary Basics

This tutorial is about operations about basis, it is mainly designed for developers, but is also useful to users.

using Yao, Yao.Intrinsics

• Storage of Computing Bases
• Binray Operations
• Iterating over Bases

Storage of Computing Bases

We use an Int type to store spin configurations, e.g. 0b011101 (29) represents qubit configuration

$\sigma_1=1, \sigma_2=0, \sigma_3=1, \sigma_4=1, \sigma_5=1, \sigma_6=0$

so we relate the configurations $\vec σ$ with integer $b$ by $b = \sum\limits_i 2^{i-1}σ_i$.

related APIs are

• integer(s) |> bitarray(nbit), transform integers to bistrings of type BitArray.
• bitstring |> packabits, transform bitstrings to integers.
• integer |> baddrs, get the locations of nonzero qubits.
@show 4 |> bitarray(5)
@show [4, 5, 6] |> bitarray(5)
@show [1, 1 , 0] |> packbits
@show [4, 5, 6] |> bitarray(5) |> packbits
4 |> bitarray(5) = Bool[false, false, true, false, false]
[4, 5, 6] |> bitarray(5) = Bool[false true false; false false true; true true true; false false false; false false false]
[1, 1, 0] |> packbits = 3
([4, 5, 6] |> bitarray(5)) |> packbits = [4, 5, 6]

Binray Operations

takebit(0b11100, 2, 3)
0x02

Masking is an important concept for binary operations, to generate a mask with specific position masked, e.g. we want to mask qubits 1, 3, 4

@show testval(0b1011, mask, 0b1001)  # true if mask outed position matches 0b1001
@show swapbits(0b1011, 0b1100)  # swap masked positions
@show setbit(0b1011, 0b1100);  # set masked positions 1
swapbits(0x0b, 0x0c) = 0x07
setbit(0x0b, 0x0c) = 0x0f

For more interesting bitwise operations, see manual page Yao.Intrinsics.

In phase estimation and HHL algorithms, we sometimes need to readouts qubits as integer or float point numbers. We can read the register in different ways, like

• bint, the integer itself
• bint_r, the integer with bits small-big end reflected.
• bfloat, the float point number 0.σ₁σ₂...σₙ.
• bfloat_r, the float point number 0.σₙ...σ₂σ₁.
@show bint(0b010101)
@show bint_r(0b010101, nbit=6)
@show bfloat(0b010101)
@show bfloat_r(0b010101, nbit=6);
bint(0x15) = 0x15
bint_r(0x15, nbit=6) = 0x2a
bfloat(0x15) = 0.65625
bfloat_r(0x15, nbit=6) = 0.328125

Notice here functions with _r ending always require nbit as an additional input parameter to help reading, which is regarded as less natural way of expressing numbers.

Iterating over Bases

Counting from 0 is very natural way of iterating quantum registers, very pity for Julia

@show basis(4);
basis(4) = 0:15

itercontrol is a complicated API, but it plays an fundamental role in high performance quantum simulation of Yao. It is used for iterating over basis in controlled way, its interface looks like

@doc itercontrol
itercontrol(num_bit::Int, poss::Vector{Int}, vals::Vector{Int}) -> IterControl

Return the iterator for basis with poss controlled to values vals, with the
total number of bits num_bit.

Here, poss is a vector of controled positions, vals is a vector of values in controled positions.

example

In a 4 qubit system, find out basis with 1st and 3rd qubits in state 0 and 1 respectively.

ic = itercontrol(4, [1,3], [0,1])
for i in ic
println(i |> bitarray(4) .|> Int)
end
[0, 0, 1, 0]
[0, 1, 1, 0]
[0, 0, 1, 1]
[0, 1, 1, 1]

Here, we have 1st and 3rd bits controlled, only 2 qubits are free, so the size of phase space here is 4.