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.85139706+0.j          0.        +0.49866638j  0.        +0.14034828j
 -0.0822025 +0.j        ]

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_3934ac68c4ae41b99faf90d704f6bd32 Circuit block cluster_8355210bd6ab4ca6b1c87500d9304bb8 Prep block cfd4e96c60454606b57c4fc66dae18c8 0 5439b9e43de34b53b112f90c5fb0abd6 cfd4e96c60454606b57c4fc66dae18c8--5439b9e43de34b53b112f90c5fb0abd6 2cacda3403ed47caa4e94b1faa747c34 1 ddee1d03f6014f34962b56aaf514c0dd RX(theta₀) 5439b9e43de34b53b112f90c5fb0abd6--ddee1d03f6014f34962b56aaf514c0dd c0b927e657f14d18907dddb3bdba1f59 RY(theta₄) ddee1d03f6014f34962b56aaf514c0dd--c0b927e657f14d18907dddb3bdba1f59 20d063099b794782bae311565880f972 RX(theta₈) c0b927e657f14d18907dddb3bdba1f59--20d063099b794782bae311565880f972 baddd71052cf471eb99ea42813ea07bf 20d063099b794782bae311565880f972--baddd71052cf471eb99ea42813ea07bf 88a7804c4dcf495eb2a1fefd83337cc9 baddd71052cf471eb99ea42813ea07bf--88a7804c4dcf495eb2a1fefd83337cc9 0458df360bc842729b312ffdc31243b9 RX(theta₁₂) 88a7804c4dcf495eb2a1fefd83337cc9--0458df360bc842729b312ffdc31243b9 0b25b56ff2044f929447391b71e6d3b1 RY(theta₁₆) 0458df360bc842729b312ffdc31243b9--0b25b56ff2044f929447391b71e6d3b1 ada7aba0d84f47dba2fa8a62450c928e RX(theta₂₀) 0b25b56ff2044f929447391b71e6d3b1--ada7aba0d84f47dba2fa8a62450c928e 97765c84c5aa497d8a1fbb964a1e9f6d ada7aba0d84f47dba2fa8a62450c928e--97765c84c5aa497d8a1fbb964a1e9f6d 23f5b41eb4ba4380a0c05cfa768f3ea9 97765c84c5aa497d8a1fbb964a1e9f6d--23f5b41eb4ba4380a0c05cfa768f3ea9 864e69dded2b4e39b5f487b1bd00dceb 23f5b41eb4ba4380a0c05cfa768f3ea9--864e69dded2b4e39b5f487b1bd00dceb 55655821e7764cfcafd4960f3fc714e4 3bfe2db109ef4bfcb7d479dbc45adee0 2cacda3403ed47caa4e94b1faa747c34--3bfe2db109ef4bfcb7d479dbc45adee0 c745fc6c8d61482fae8dd05e31c88148 2 2a1f4c8591174e0d9bfc364bc0e3f20a RX(theta₁) 3bfe2db109ef4bfcb7d479dbc45adee0--2a1f4c8591174e0d9bfc364bc0e3f20a 4d16d01a1c20495ba060acd8c4436e71 RY(theta₅) 2a1f4c8591174e0d9bfc364bc0e3f20a--4d16d01a1c20495ba060acd8c4436e71 661c2ce281bd4467b6e0297a996418c1 RX(theta₉) 4d16d01a1c20495ba060acd8c4436e71--661c2ce281bd4467b6e0297a996418c1 d2404308d4114597a85d0e0bf796aa88 X 661c2ce281bd4467b6e0297a996418c1--d2404308d4114597a85d0e0bf796aa88 d2404308d4114597a85d0e0bf796aa88--baddd71052cf471eb99ea42813ea07bf 0f2569ce098449e28ce66129194f9a02 d2404308d4114597a85d0e0bf796aa88--0f2569ce098449e28ce66129194f9a02 d988cf5e1a18455999c10d66579c0269 RX(theta₁₃) 0f2569ce098449e28ce66129194f9a02--d988cf5e1a18455999c10d66579c0269 5a5f224da6444cb88c9c463b2e883a4b RY(theta₁₇) d988cf5e1a18455999c10d66579c0269--5a5f224da6444cb88c9c463b2e883a4b 24840e9b4ae549919e3b244113e60d28 RX(theta₂₁) 5a5f224da6444cb88c9c463b2e883a4b--24840e9b4ae549919e3b244113e60d28 e7a356803fb34764b7ff0b70f7b5b97e X 24840e9b4ae549919e3b244113e60d28--e7a356803fb34764b7ff0b70f7b5b97e e7a356803fb34764b7ff0b70f7b5b97e--97765c84c5aa497d8a1fbb964a1e9f6d 028f51b761a943caaea4bcddb569c804 e7a356803fb34764b7ff0b70f7b5b97e--028f51b761a943caaea4bcddb569c804 028f51b761a943caaea4bcddb569c804--55655821e7764cfcafd4960f3fc714e4 a101340f9fff429fa6c878ee2ea12607 d0cf92d5e9af4c00a41ed90f60c87212 c745fc6c8d61482fae8dd05e31c88148--d0cf92d5e9af4c00a41ed90f60c87212 75abf5197bbd4e979a642e0bd42fa138 3 db0200d09d9b4726973d174cf6f15b93 RX(theta₂) d0cf92d5e9af4c00a41ed90f60c87212--db0200d09d9b4726973d174cf6f15b93 d064e403bfae482cacc7d7d4f9d32be0 RY(theta₆) db0200d09d9b4726973d174cf6f15b93--d064e403bfae482cacc7d7d4f9d32be0 d446a35fb988474eb79b5a9ef20a1d18 RX(theta₁₀) d064e403bfae482cacc7d7d4f9d32be0--d446a35fb988474eb79b5a9ef20a1d18 707a0f63a38c43fa8d8b0e52d0f53a08 d446a35fb988474eb79b5a9ef20a1d18--707a0f63a38c43fa8d8b0e52d0f53a08 cdc35221e76d439c9de946db0e6a3782 X 707a0f63a38c43fa8d8b0e52d0f53a08--cdc35221e76d439c9de946db0e6a3782 cdc35221e76d439c9de946db0e6a3782--0f2569ce098449e28ce66129194f9a02 18acaac294af45fab459c7c369ab087c RX(theta₁₄) cdc35221e76d439c9de946db0e6a3782--18acaac294af45fab459c7c369ab087c 52a8f304c6b1447d9fd06ff7da83a120 RY(theta₁₈) 18acaac294af45fab459c7c369ab087c--52a8f304c6b1447d9fd06ff7da83a120 a12d872ed5c8405794b79ad7ef165cce RX(theta₂₂) 52a8f304c6b1447d9fd06ff7da83a120--a12d872ed5c8405794b79ad7ef165cce d2fa75f75cc74c389fd77ee9eb9a8e8a a12d872ed5c8405794b79ad7ef165cce--d2fa75f75cc74c389fd77ee9eb9a8e8a c03bc8e9de7e4d5696519533a5831957 X d2fa75f75cc74c389fd77ee9eb9a8e8a--c03bc8e9de7e4d5696519533a5831957 c03bc8e9de7e4d5696519533a5831957--028f51b761a943caaea4bcddb569c804 c03bc8e9de7e4d5696519533a5831957--a101340f9fff429fa6c878ee2ea12607 f98362f336374dedb4acac86d07cd997 e5e64b7fbb2f4fcda42e6296c717ead0 X 75abf5197bbd4e979a642e0bd42fa138--e5e64b7fbb2f4fcda42e6296c717ead0 70aa09a0998e4b96bb9467177b503bb1 RX(theta₃) e5e64b7fbb2f4fcda42e6296c717ead0--70aa09a0998e4b96bb9467177b503bb1 49730a4027ed4699b2a24ebc31b7b23d RY(theta₇) 70aa09a0998e4b96bb9467177b503bb1--49730a4027ed4699b2a24ebc31b7b23d 6a978faf41e14665b1e7b5b7cfe25cf7 RX(theta₁₁) 49730a4027ed4699b2a24ebc31b7b23d--6a978faf41e14665b1e7b5b7cfe25cf7 3df93b55231147a89bc5aa754bfe135a X 6a978faf41e14665b1e7b5b7cfe25cf7--3df93b55231147a89bc5aa754bfe135a 3df93b55231147a89bc5aa754bfe135a--707a0f63a38c43fa8d8b0e52d0f53a08 d86ee0f188d748e086ba805f6e3852a0 3df93b55231147a89bc5aa754bfe135a--d86ee0f188d748e086ba805f6e3852a0 788f074b6a2142d596fdd0612d488b52 RX(theta₁₅) d86ee0f188d748e086ba805f6e3852a0--788f074b6a2142d596fdd0612d488b52 d047abc2dc9942a0b93d60d75afcfa53 RY(theta₁₉) 788f074b6a2142d596fdd0612d488b52--d047abc2dc9942a0b93d60d75afcfa53 6897cdf0cd344c5faf17d6e0d3345269 RX(theta₂₃) d047abc2dc9942a0b93d60d75afcfa53--6897cdf0cd344c5faf17d6e0d3345269 83f1187f3385478aa06542b0588ac576 X 6897cdf0cd344c5faf17d6e0d3345269--83f1187f3385478aa06542b0588ac576 83f1187f3385478aa06542b0588ac576--d2fa75f75cc74c389fd77ee9eb9a8e8a 5285e2e369934727bc1d405f33d82589 83f1187f3385478aa06542b0588ac576--5285e2e369934727bc1d405f33d82589 5285e2e369934727bc1d405f33d82589--f98362f336374dedb4acac86d07cd997
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, 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, 1.+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.1643-0.0622j, -0.5407+0.1029j,  0.1102-0.1265j, -0.6922+0.0940j,
         -0.1508-0.2266j, -0.1701+0.0631j,  0.1501-0.0578j, -0.0811+0.1033j],
        [-0.0584-0.0556j, -0.0646+0.2321j,  0.2937-0.1183j,  0.0567+0.0674j,
          0.3735+0.2155j,  0.2888-0.0695j, -0.3494-0.3858j, -0.0950+0.5228j]])

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)
├── 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]])