Skip to content

State initialization

Qadence offers convenience routines for preparing initial quantum states. These routines are divided into two approaches:

  • As a dense matrix.
  • From a suitable quantum circuit. This is available for every backend and it should be added in front of the desired quantum circuit to simulate.

Let's illustrate the usage of the state preparation routine.

from qadence import random_state, product_state, is_normalized, StateGeneratorType

# Random initial state.
# the default `type` is StateGeneratorType.HaarMeasureFast
state = random_state(n_qubits=2, type=StateGeneratorType.RANDOM_ROTATIONS)

# Check the normalization.
assert is_normalized(state)

# Product state from a given bitstring.
# NB: Qadence follows the big endian convention.
state = product_state("01")
Random initial state generated with rotations:

state = [0.50929534+0.j         0.24053405+0.j         0.        -0.74715619j
 0.        -0.35287286j]

Product state corresponding to bitstring '01':

state = [0.+0.j 1.+0.j 0.+0.j 0.+0.j]

Now we see how to generate the product state corresponding to the one above with a suitable quantum circuit.

from qadence import product_block, tag, hea, QuantumCircuit
from qadence.draw import display

state_prep_block = product_block("01")
# display(state_prep_block)

# Let's now prepare a circuit.
n_qubits = 4

state_prep_block = product_block("0001")
tag(state_prep_block, "Prep block")

circuit_block = tag(hea(n_qubits, depth = 2), "Circuit block")

qc_with_state_prep = QuantumCircuit(n_qubits, state_prep_block, circuit_block)
%3 cluster_8cf781b043394bc4a9817069d3456417 Circuit block cluster_4692c63c275a4fa99d80957e5effb0da Prep block ad3d01f0f6984c3daed70002aee8b6f9 0 2f806f2fef714faf84a5d5f3622721e4 ad3d01f0f6984c3daed70002aee8b6f9--2f806f2fef714faf84a5d5f3622721e4 1667bdc0632f4bc2a460df354fa69445 1 d9bdd4a8b4154dbba0e61f8358199700 RX(theta₀) 2f806f2fef714faf84a5d5f3622721e4--d9bdd4a8b4154dbba0e61f8358199700 5f8e6212c93a42919ee6034c2ae3aea8 RY(theta₄) d9bdd4a8b4154dbba0e61f8358199700--5f8e6212c93a42919ee6034c2ae3aea8 5d3fe7eae6aa44bdab78254ef4ef8413 RX(theta₈) 5f8e6212c93a42919ee6034c2ae3aea8--5d3fe7eae6aa44bdab78254ef4ef8413 5ff6d2d4121a44f29d311768e0f86c74 5d3fe7eae6aa44bdab78254ef4ef8413--5ff6d2d4121a44f29d311768e0f86c74 0479f480753843e5918db285d797f289 5ff6d2d4121a44f29d311768e0f86c74--0479f480753843e5918db285d797f289 45e932ceb1494e5080139291b818095f RX(theta₁₂) 0479f480753843e5918db285d797f289--45e932ceb1494e5080139291b818095f e77af8b454494927ade307b45851f19e RY(theta₁₆) 45e932ceb1494e5080139291b818095f--e77af8b454494927ade307b45851f19e 88ef851599bc4a898b98f61b8f15c4cc RX(theta₂₀) e77af8b454494927ade307b45851f19e--88ef851599bc4a898b98f61b8f15c4cc 2d6a756dcdec4606b6668b0fc2384ffb 88ef851599bc4a898b98f61b8f15c4cc--2d6a756dcdec4606b6668b0fc2384ffb bc2ff7703c84473592d678f1647e9945 2d6a756dcdec4606b6668b0fc2384ffb--bc2ff7703c84473592d678f1647e9945 9ab2c451e7b446e4898cf26a532fe841 bc2ff7703c84473592d678f1647e9945--9ab2c451e7b446e4898cf26a532fe841 df0aeb6ead904489a6a9b72d795058a9 03136a1aa67443869d2d66a4db123bac 1667bdc0632f4bc2a460df354fa69445--03136a1aa67443869d2d66a4db123bac 439e83f8727345569a635ac0f4aae484 2 a09a75df57ed44b7864b4d2e4d5f516c RX(theta₁) 03136a1aa67443869d2d66a4db123bac--a09a75df57ed44b7864b4d2e4d5f516c 392e8f04310647a48c57139eb0a057a9 RY(theta₅) a09a75df57ed44b7864b4d2e4d5f516c--392e8f04310647a48c57139eb0a057a9 3d0fa604d9cc4d3f931eef934593f6d8 RX(theta₉) 392e8f04310647a48c57139eb0a057a9--3d0fa604d9cc4d3f931eef934593f6d8 c5c863368a304abaa6898db3d0d8c7f2 X 3d0fa604d9cc4d3f931eef934593f6d8--c5c863368a304abaa6898db3d0d8c7f2 c5c863368a304abaa6898db3d0d8c7f2--5ff6d2d4121a44f29d311768e0f86c74 2babfd31adc44b398c51a03581af048e c5c863368a304abaa6898db3d0d8c7f2--2babfd31adc44b398c51a03581af048e 7b2f3b23e5b44d958faa3b29d60cecef RX(theta₁₃) 2babfd31adc44b398c51a03581af048e--7b2f3b23e5b44d958faa3b29d60cecef 39b698b635784e68bc4b8e44471f6bd7 RY(theta₁₇) 7b2f3b23e5b44d958faa3b29d60cecef--39b698b635784e68bc4b8e44471f6bd7 bf8e50fd74fe49f8954080029dac13f0 RX(theta₂₁) 39b698b635784e68bc4b8e44471f6bd7--bf8e50fd74fe49f8954080029dac13f0 20d6bff8e8b4411db931215b833b3ce7 X bf8e50fd74fe49f8954080029dac13f0--20d6bff8e8b4411db931215b833b3ce7 20d6bff8e8b4411db931215b833b3ce7--2d6a756dcdec4606b6668b0fc2384ffb fbf941b3c574403cacd81a26cf120c22 20d6bff8e8b4411db931215b833b3ce7--fbf941b3c574403cacd81a26cf120c22 fbf941b3c574403cacd81a26cf120c22--df0aeb6ead904489a6a9b72d795058a9 b51abd2f715048cd9a8f54a368e46aee 347696d4b5374af38c0f5bf7c71b85a2 439e83f8727345569a635ac0f4aae484--347696d4b5374af38c0f5bf7c71b85a2 9da50bb4fde842918bc3c49700b9e2ac 3 c9f3865d14264722a53c78824f3294a0 RX(theta₂) 347696d4b5374af38c0f5bf7c71b85a2--c9f3865d14264722a53c78824f3294a0 46422b39d250425d83cdac9c25edac7c RY(theta₆) c9f3865d14264722a53c78824f3294a0--46422b39d250425d83cdac9c25edac7c 4f2674a9482a48b3a37a4f0cb2cc5317 RX(theta₁₀) 46422b39d250425d83cdac9c25edac7c--4f2674a9482a48b3a37a4f0cb2cc5317 4d04cc969804421bb96568462b2369b5 4f2674a9482a48b3a37a4f0cb2cc5317--4d04cc969804421bb96568462b2369b5 9e368c867bfb4a188afc62fdcf766098 X 4d04cc969804421bb96568462b2369b5--9e368c867bfb4a188afc62fdcf766098 9e368c867bfb4a188afc62fdcf766098--2babfd31adc44b398c51a03581af048e 3b2f52be388b499cb5590af54575e5c1 RX(theta₁₄) 9e368c867bfb4a188afc62fdcf766098--3b2f52be388b499cb5590af54575e5c1 3c42e1a7c2eb4cf78d4ef9ce2a231e8c RY(theta₁₈) 3b2f52be388b499cb5590af54575e5c1--3c42e1a7c2eb4cf78d4ef9ce2a231e8c 78076661e4a743c29cbc854803815ad5 RX(theta₂₂) 3c42e1a7c2eb4cf78d4ef9ce2a231e8c--78076661e4a743c29cbc854803815ad5 e5fd5d5f34c7458ca552c003fdb51b9d 78076661e4a743c29cbc854803815ad5--e5fd5d5f34c7458ca552c003fdb51b9d bc2a69b72407455cb80bb63d1bc07c3f X e5fd5d5f34c7458ca552c003fdb51b9d--bc2a69b72407455cb80bb63d1bc07c3f bc2a69b72407455cb80bb63d1bc07c3f--fbf941b3c574403cacd81a26cf120c22 bc2a69b72407455cb80bb63d1bc07c3f--b51abd2f715048cd9a8f54a368e46aee 38a293e3d00f4ab987f606e015cfe37a b5cb09f7aea2417cbafa06e1220542fa X 9da50bb4fde842918bc3c49700b9e2ac--b5cb09f7aea2417cbafa06e1220542fa 5054c9cca39846d8b5a8954ee0866f03 RX(theta₃) b5cb09f7aea2417cbafa06e1220542fa--5054c9cca39846d8b5a8954ee0866f03 5adf2e117f3e477eaaeaf3832d5d29a2 RY(theta₇) 5054c9cca39846d8b5a8954ee0866f03--5adf2e117f3e477eaaeaf3832d5d29a2 55a3577f84d74acd8f43f082509f9430 RX(theta₁₁) 5adf2e117f3e477eaaeaf3832d5d29a2--55a3577f84d74acd8f43f082509f9430 6e23baa66f164b13bb86b996d60274a7 X 55a3577f84d74acd8f43f082509f9430--6e23baa66f164b13bb86b996d60274a7 6e23baa66f164b13bb86b996d60274a7--4d04cc969804421bb96568462b2369b5 b0aa8e7b6258405ca5e9e69bf7369fe8 6e23baa66f164b13bb86b996d60274a7--b0aa8e7b6258405ca5e9e69bf7369fe8 22ad0bafe5cb4411830e921aa5a4dad6 RX(theta₁₅) b0aa8e7b6258405ca5e9e69bf7369fe8--22ad0bafe5cb4411830e921aa5a4dad6 dbd9ad62a95643d381912d06463adbef RY(theta₁₉) 22ad0bafe5cb4411830e921aa5a4dad6--dbd9ad62a95643d381912d06463adbef ea877ac23cd94035b79dd553eadd045e RX(theta₂₃) dbd9ad62a95643d381912d06463adbef--ea877ac23cd94035b79dd553eadd045e 9a316c0d1bd0417db37cd4c5355ae8d7 X ea877ac23cd94035b79dd553eadd045e--9a316c0d1bd0417db37cd4c5355ae8d7 9a316c0d1bd0417db37cd4c5355ae8d7--e5fd5d5f34c7458ca552c003fdb51b9d 193f172278b946ecb5ae314a6ce61817 9a316c0d1bd0417db37cd4c5355ae8d7--193f172278b946ecb5ae314a6ce61817 193f172278b946ecb5ae314a6ce61817--38a293e3d00f4ab987f606e015cfe37a
Several standard quantum states can be conveniently initialized in Qadence, both in statevector form as well as in block form as shown in following.

State vector initialization

Qadence offers a number of constructor functions for state vector preparation.

from qadence import uniform_state, zero_state, one_state

n_qubits = 3
batch_size = 2

uniform_state = uniform_state(n_qubits, batch_size)
zero_state = zero_state(n_qubits, batch_size)
one_state = one_state(n_qubits, batch_size)
Uniform state = 

tensor([[0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j,
         0.3536+0.j],
        [0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j,
         0.3536+0.j]])
Zero state = 

tensor([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
        [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])
One state = 

tensor([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
        [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])

As already seen, product states can be easily created, even in batches:

from qadence import product_state, rand_product_state

# From a bitsring "100"
prod_state = product_state("100", batch_size)

# Or a random product state
rand_state = rand_product_state(n_qubits, batch_size)
Product state = 

tensor([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])

Random state = 

tensor([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
        [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])

Creating a GHZ state:

from qadence import ghz_state

ghz = ghz_state(n_qubits, batch_size)
GHZ state = 

tensor([[0.7071+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j,
         0.7071+0.j],
        [0.7071+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j,
         0.7071+0.j]])

Creating a random state uniformly sampled from a Haar measure:

from qadence import random_state

rand_haar_state = random_state(n_qubits, batch_size)
Random state from Haar = 

tensor([[ 0.1907-0.2530j, -0.1918-0.0710j,  0.3923-0.3315j, -0.0455-0.1129j,
          0.1975-0.0792j,  0.5236+0.0577j,  0.2448-0.1669j, -0.4084+0.0428j],
        [-0.0952-0.1626j,  0.1650+0.0488j,  0.0936-0.3226j,  0.1072+0.4489j,
          0.0674-0.1573j, -0.1308+0.6493j, -0.2529-0.1209j, -0.1880+0.1647j]])

Custom initial states can then be passed to either run, sample and expectation through the state argument

from qadence import random_state, product_state, CNOT, run

init_state = product_state("10")
final_state = run(CNOT(0, 1), state=init_state)
Final state = tensor([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])

Block initialization

Not all backends support custom statevector initialization, however previous utility functions have their counterparts to initialize the respective blocks:

from qadence import uniform_block, one_block

n_qubits = 3

uniform_block = uniform_block(n_qubits)

one_block = one_block(n_qubits)
KronBlock(0,1,2)
├── H(0)
├── H(1)
└── H(2)
KronBlock(0,1,2)
├── X(0)
├── X(1)
└── X(2)

Similarly, for product states:

from qadence import product_block, rand_product_block

product_block = product_block("100")

rand_product_block = rand_product_block(n_qubits)
KronBlock(0,1,2)
├── X(0)
├── I(1)
└── I(2)
KronBlock(0,1,2)
├── I(0)
├── I(1)
└── X(2)

And GHZ states:

from qadence import ghz_block

ghz_block = ghz_block(n_qubits)
ChainBlock(0,1,2)
├── H(0)
└── ChainBlock(0,1,2)
    ├── CNOT(0, 1)
    └── CNOT(1, 2)

Initial state blocks can simply be chained at the start of a given circuit.

Utility functions

Some state vector utility functions are also available. We can easily create the probability mass function of a given statevector using torch.distributions.Categorical

from qadence import random_state, pmf

n_qubits = 3

state = random_state(n_qubits)
distribution = pmf(state)
Categorical(probs: torch.Size([1, 8]))

We can also check if a state is normalized:

from qadence import random_state, is_normalized

state = random_state(n_qubits)
print(is_normalized(state))
True

Or normalize a state:

import torch
from qadence import normalize, is_normalized

state = torch.tensor([[1, 1, 1, 1]], dtype = torch.cdouble)
print(normalize(state))
tensor([[0.5000+0.j, 0.5000+0.j, 0.5000+0.j, 0.5000+0.j]])