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.58729291+0.j         0.        +0.04520839j 0.80572725+0.j
 0.        +0.06202294j]

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_a309924e874e4a51882a2a3c76cd3c62 Circuit block cluster_153faf85c16e47b98907d57b7e9cf033 Prep block 37749086c3624f6b8b88ef331da322d9 0 1bbcf20c30c54dc788b7e7ce1f36553f 37749086c3624f6b8b88ef331da322d9--1bbcf20c30c54dc788b7e7ce1f36553f 2c23699454ec481989b79fc60cfa3199 1 c0e193a641f548328ca6771f4698d7ea RX(theta₀) 1bbcf20c30c54dc788b7e7ce1f36553f--c0e193a641f548328ca6771f4698d7ea 27d4908deb5f403496c9fd37326eb2bb RY(theta₄) c0e193a641f548328ca6771f4698d7ea--27d4908deb5f403496c9fd37326eb2bb aaa0832408a14e7c8b2beb4ddbfe8e6d RX(theta₈) 27d4908deb5f403496c9fd37326eb2bb--aaa0832408a14e7c8b2beb4ddbfe8e6d 12bb8312f66d4bf082e762ed1250b8bb aaa0832408a14e7c8b2beb4ddbfe8e6d--12bb8312f66d4bf082e762ed1250b8bb c8761a5c38b44279a11a229b2f77795d 12bb8312f66d4bf082e762ed1250b8bb--c8761a5c38b44279a11a229b2f77795d a64d99e1e2dd48ff89d247321f0c55a5 RX(theta₁₂) c8761a5c38b44279a11a229b2f77795d--a64d99e1e2dd48ff89d247321f0c55a5 21a1a0280f1340dd9ea09e8b08c168e4 RY(theta₁₆) a64d99e1e2dd48ff89d247321f0c55a5--21a1a0280f1340dd9ea09e8b08c168e4 c711177803cf45488bfb7e4ea2658c58 RX(theta₂₀) 21a1a0280f1340dd9ea09e8b08c168e4--c711177803cf45488bfb7e4ea2658c58 9d560866f28a4a888c96325bbaaad82f c711177803cf45488bfb7e4ea2658c58--9d560866f28a4a888c96325bbaaad82f 3b94d68b194e497e84390e75773e8d89 9d560866f28a4a888c96325bbaaad82f--3b94d68b194e497e84390e75773e8d89 103075b3e92e4fabb860fdc8474bd52c 3b94d68b194e497e84390e75773e8d89--103075b3e92e4fabb860fdc8474bd52c 01cfcd17be50431c9995f8dc741210f4 5f225d2bf1ef4daba7220e1ee94e2c6c 2c23699454ec481989b79fc60cfa3199--5f225d2bf1ef4daba7220e1ee94e2c6c aa8b6e3636e143048d96c6885d5234d0 2 e59f8933a7514e27add0709f95ad37bb RX(theta₁) 5f225d2bf1ef4daba7220e1ee94e2c6c--e59f8933a7514e27add0709f95ad37bb eccf6a0e31084b468512864d7860817d RY(theta₅) e59f8933a7514e27add0709f95ad37bb--eccf6a0e31084b468512864d7860817d b0e40febbc2f4cc69b1045c5039e4857 RX(theta₉) eccf6a0e31084b468512864d7860817d--b0e40febbc2f4cc69b1045c5039e4857 1957443d32044ebcb7baae4beaad5520 X b0e40febbc2f4cc69b1045c5039e4857--1957443d32044ebcb7baae4beaad5520 1957443d32044ebcb7baae4beaad5520--12bb8312f66d4bf082e762ed1250b8bb 482aa206068d486f9439d313f28b545e 1957443d32044ebcb7baae4beaad5520--482aa206068d486f9439d313f28b545e acfb50a5a5214d678522bcee1a745163 RX(theta₁₃) 482aa206068d486f9439d313f28b545e--acfb50a5a5214d678522bcee1a745163 c1d2ca743fa847529dcb12f31d9bdcfd RY(theta₁₇) acfb50a5a5214d678522bcee1a745163--c1d2ca743fa847529dcb12f31d9bdcfd 1b9c7fb8abf249ad93fd741f4f52e8d2 RX(theta₂₁) c1d2ca743fa847529dcb12f31d9bdcfd--1b9c7fb8abf249ad93fd741f4f52e8d2 79f7eb61aac8421b9226764c1fad05b1 X 1b9c7fb8abf249ad93fd741f4f52e8d2--79f7eb61aac8421b9226764c1fad05b1 79f7eb61aac8421b9226764c1fad05b1--9d560866f28a4a888c96325bbaaad82f 282ac4a76711421babd30404f27252da 79f7eb61aac8421b9226764c1fad05b1--282ac4a76711421babd30404f27252da 282ac4a76711421babd30404f27252da--01cfcd17be50431c9995f8dc741210f4 0687b978f354459f9afb68d761bf41dc caaac81c892e49c8a8aa21d324427b6b aa8b6e3636e143048d96c6885d5234d0--caaac81c892e49c8a8aa21d324427b6b a6bc7d7b15c6416ebd0558d70b981332 3 613f65bad9ac45b0b6fc48cfbb5f998d RX(theta₂) caaac81c892e49c8a8aa21d324427b6b--613f65bad9ac45b0b6fc48cfbb5f998d 14b23220cd51499e833a1e885cc8f5bd RY(theta₆) 613f65bad9ac45b0b6fc48cfbb5f998d--14b23220cd51499e833a1e885cc8f5bd caa980504eb34d829846d8f9e1d38f9a RX(theta₁₀) 14b23220cd51499e833a1e885cc8f5bd--caa980504eb34d829846d8f9e1d38f9a 5096f8d50e1f40988bdc544a54d37ca3 caa980504eb34d829846d8f9e1d38f9a--5096f8d50e1f40988bdc544a54d37ca3 9a654c54775648188a946ba0fc9868cc X 5096f8d50e1f40988bdc544a54d37ca3--9a654c54775648188a946ba0fc9868cc 9a654c54775648188a946ba0fc9868cc--482aa206068d486f9439d313f28b545e 7950f071934340d08cc64283ae6a91bf RX(theta₁₄) 9a654c54775648188a946ba0fc9868cc--7950f071934340d08cc64283ae6a91bf 93e63d4990424f1c9b3db1135b3819cb RY(theta₁₈) 7950f071934340d08cc64283ae6a91bf--93e63d4990424f1c9b3db1135b3819cb 4d61d1ef333b4572b87bd143c29e91b4 RX(theta₂₂) 93e63d4990424f1c9b3db1135b3819cb--4d61d1ef333b4572b87bd143c29e91b4 7f73f20175f04b30afacc39f9336b9d6 4d61d1ef333b4572b87bd143c29e91b4--7f73f20175f04b30afacc39f9336b9d6 2e144c6b6d614781bbc98ee5c0d7036f X 7f73f20175f04b30afacc39f9336b9d6--2e144c6b6d614781bbc98ee5c0d7036f 2e144c6b6d614781bbc98ee5c0d7036f--282ac4a76711421babd30404f27252da 2e144c6b6d614781bbc98ee5c0d7036f--0687b978f354459f9afb68d761bf41dc a0ce6d818a084e88ac5aa822092fa93b 0706a99062d64115914d74742af5cdd2 X a6bc7d7b15c6416ebd0558d70b981332--0706a99062d64115914d74742af5cdd2 0d2688006a8443389014f32c639ad034 RX(theta₃) 0706a99062d64115914d74742af5cdd2--0d2688006a8443389014f32c639ad034 8569c30243244d728901a11043e01082 RY(theta₇) 0d2688006a8443389014f32c639ad034--8569c30243244d728901a11043e01082 fbae3d493b7241539c9003fa181e53e6 RX(theta₁₁) 8569c30243244d728901a11043e01082--fbae3d493b7241539c9003fa181e53e6 3da3cd6a706a4bf190342d67bf21078f X fbae3d493b7241539c9003fa181e53e6--3da3cd6a706a4bf190342d67bf21078f 3da3cd6a706a4bf190342d67bf21078f--5096f8d50e1f40988bdc544a54d37ca3 7d3d1a57b976455db859f799e1df4c79 3da3cd6a706a4bf190342d67bf21078f--7d3d1a57b976455db859f799e1df4c79 2453b3722b5e4deba2c0aafdec209902 RX(theta₁₅) 7d3d1a57b976455db859f799e1df4c79--2453b3722b5e4deba2c0aafdec209902 fc174861b71744aab7d994343493ca4e RY(theta₁₉) 2453b3722b5e4deba2c0aafdec209902--fc174861b71744aab7d994343493ca4e dedf12fb455d447eaeebcf3516179a2e RX(theta₂₃) fc174861b71744aab7d994343493ca4e--dedf12fb455d447eaeebcf3516179a2e de076c2e4b4f48b1a14b2a1df914ccf4 X dedf12fb455d447eaeebcf3516179a2e--de076c2e4b4f48b1a14b2a1df914ccf4 de076c2e4b4f48b1a14b2a1df914ccf4--7f73f20175f04b30afacc39f9336b9d6 010ff3bf92fb4a9ead8091d861f9ffc9 de076c2e4b4f48b1a14b2a1df914ccf4--010ff3bf92fb4a9ead8091d861f9ffc9 010ff3bf92fb4a9ead8091d861f9ffc9--a0ce6d818a084e88ac5aa822092fa93b
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],
        [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, 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]])

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.3367+0.1492j, -0.2387-0.4529j, -0.0397+0.1336j, -0.1125+0.5659j,
         -0.0703-0.0669j, -0.0778+0.2793j,  0.3534-0.1424j,  0.0682+0.0811j],
        [ 0.3436+0.2393j,  0.0505-0.0122j, -0.0484-0.1730j, -0.0440+0.2970j,
          0.3615+0.2362j,  0.2817-0.0456j,  0.2953+0.4642j, -0.2217+0.2824j]])

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)
├── X(0)
├── X(1)
└── I(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]])