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.61294422+0.j          0.        -0.62548256j -0.33789941+0.j
  0.        +0.34481145j]

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_20febeb5e5fd49b0b982acfc0c29c83d Circuit block cluster_e6ba4a54770b417dbfaa8f31684d3a04 Prep block cd5c9a6bd6774a018e0e1450efc49d4b 0 5c70ab0f5fc845048d33c98785b0cc75 cd5c9a6bd6774a018e0e1450efc49d4b--5c70ab0f5fc845048d33c98785b0cc75 2d1efb4207b54ea68288444a75211417 1 d689ae40ccf64ad49ef3a18256e09f43 RX(theta₀) 5c70ab0f5fc845048d33c98785b0cc75--d689ae40ccf64ad49ef3a18256e09f43 b4351b460aeb4d5b81994efce6978c9b RY(theta₄) d689ae40ccf64ad49ef3a18256e09f43--b4351b460aeb4d5b81994efce6978c9b 4414090d3ed248958f2ed0124649748f RX(theta₈) b4351b460aeb4d5b81994efce6978c9b--4414090d3ed248958f2ed0124649748f ca609c3923584ed087bb8a4fe006b215 4414090d3ed248958f2ed0124649748f--ca609c3923584ed087bb8a4fe006b215 30ad094c6a3944e0b8a8a7fb10b59a7f ca609c3923584ed087bb8a4fe006b215--30ad094c6a3944e0b8a8a7fb10b59a7f 8b1c4fb2ae9e471f88e48b3ddf5073e7 RX(theta₁₂) 30ad094c6a3944e0b8a8a7fb10b59a7f--8b1c4fb2ae9e471f88e48b3ddf5073e7 ae1b54cf806f463595c27d55ae7382b0 RY(theta₁₆) 8b1c4fb2ae9e471f88e48b3ddf5073e7--ae1b54cf806f463595c27d55ae7382b0 6d5443466459448fb53807e5e066466a RX(theta₂₀) ae1b54cf806f463595c27d55ae7382b0--6d5443466459448fb53807e5e066466a 68837d1e8bdf4cbba5a01dfef8f2138d 6d5443466459448fb53807e5e066466a--68837d1e8bdf4cbba5a01dfef8f2138d 4afee3b1231945feb09e5d9256347004 68837d1e8bdf4cbba5a01dfef8f2138d--4afee3b1231945feb09e5d9256347004 817d1cd7287642b8bf61f0945b0259c0 4afee3b1231945feb09e5d9256347004--817d1cd7287642b8bf61f0945b0259c0 85e0feb5d4464421b40584ff5048fb6e 56e5d8e3b0a0496793a9e514b90f2a50 2d1efb4207b54ea68288444a75211417--56e5d8e3b0a0496793a9e514b90f2a50 37d6051f10ba4c87b7228632cd4ae186 2 94db8bc5f6a34315b682e4de9c4f05c8 RX(theta₁) 56e5d8e3b0a0496793a9e514b90f2a50--94db8bc5f6a34315b682e4de9c4f05c8 bb0a067d356747f883a56d4fc82be59f RY(theta₅) 94db8bc5f6a34315b682e4de9c4f05c8--bb0a067d356747f883a56d4fc82be59f 1cef57bf06584f84b3d3e61badd8b0f0 RX(theta₉) bb0a067d356747f883a56d4fc82be59f--1cef57bf06584f84b3d3e61badd8b0f0 2c93a7aba07b4fea97d4f9591ac6e931 X 1cef57bf06584f84b3d3e61badd8b0f0--2c93a7aba07b4fea97d4f9591ac6e931 2c93a7aba07b4fea97d4f9591ac6e931--ca609c3923584ed087bb8a4fe006b215 1444e3bd63734c86b3f1e3fe554e8456 2c93a7aba07b4fea97d4f9591ac6e931--1444e3bd63734c86b3f1e3fe554e8456 41098d66cdf24b8285fe51a09a2b2551 RX(theta₁₃) 1444e3bd63734c86b3f1e3fe554e8456--41098d66cdf24b8285fe51a09a2b2551 8e67ee837c7843c3a8a1e09d6f85cf95 RY(theta₁₇) 41098d66cdf24b8285fe51a09a2b2551--8e67ee837c7843c3a8a1e09d6f85cf95 e7fae26832704489b748bd40e7feab29 RX(theta₂₁) 8e67ee837c7843c3a8a1e09d6f85cf95--e7fae26832704489b748bd40e7feab29 2ce8c7e60cae4cafaeb8ccfed7577abb X e7fae26832704489b748bd40e7feab29--2ce8c7e60cae4cafaeb8ccfed7577abb 2ce8c7e60cae4cafaeb8ccfed7577abb--68837d1e8bdf4cbba5a01dfef8f2138d d330f22b571b45a2a4be575e9965a33f 2ce8c7e60cae4cafaeb8ccfed7577abb--d330f22b571b45a2a4be575e9965a33f d330f22b571b45a2a4be575e9965a33f--85e0feb5d4464421b40584ff5048fb6e d373beb3c5dd44c4966633c47dbb1c01 d08098e9a8724055b91ec94a4dfa85d6 37d6051f10ba4c87b7228632cd4ae186--d08098e9a8724055b91ec94a4dfa85d6 df3d6c9fc9d64633b5ee410def9c0210 3 063d7d70685c4d258617c3ee2f089e1e RX(theta₂) d08098e9a8724055b91ec94a4dfa85d6--063d7d70685c4d258617c3ee2f089e1e 6f46d5e5bb894ded858914759c78db44 RY(theta₆) 063d7d70685c4d258617c3ee2f089e1e--6f46d5e5bb894ded858914759c78db44 0f0ae78f1b8d446e9dce3755dc8f07f4 RX(theta₁₀) 6f46d5e5bb894ded858914759c78db44--0f0ae78f1b8d446e9dce3755dc8f07f4 b018adb1df334e6a8deaf58afaa6beba 0f0ae78f1b8d446e9dce3755dc8f07f4--b018adb1df334e6a8deaf58afaa6beba c18fdaa7d71a4bb28c19e122eef5f205 X b018adb1df334e6a8deaf58afaa6beba--c18fdaa7d71a4bb28c19e122eef5f205 c18fdaa7d71a4bb28c19e122eef5f205--1444e3bd63734c86b3f1e3fe554e8456 f59c42e2c2fe43be978e6be7dfefe921 RX(theta₁₄) c18fdaa7d71a4bb28c19e122eef5f205--f59c42e2c2fe43be978e6be7dfefe921 8149565607d1487c9a259aa235fdf876 RY(theta₁₈) f59c42e2c2fe43be978e6be7dfefe921--8149565607d1487c9a259aa235fdf876 ac079ccabc1f4ba0be9bbd4b3a714685 RX(theta₂₂) 8149565607d1487c9a259aa235fdf876--ac079ccabc1f4ba0be9bbd4b3a714685 0abf807903654231a713a5137fdaa830 ac079ccabc1f4ba0be9bbd4b3a714685--0abf807903654231a713a5137fdaa830 3c3897b8a9b5475e9f5ab73551ddef90 X 0abf807903654231a713a5137fdaa830--3c3897b8a9b5475e9f5ab73551ddef90 3c3897b8a9b5475e9f5ab73551ddef90--d330f22b571b45a2a4be575e9965a33f 3c3897b8a9b5475e9f5ab73551ddef90--d373beb3c5dd44c4966633c47dbb1c01 05cc2aee09754e70bb64d5a876019be3 86270d1c2a8548b8aaf9c5a862bc502c X df3d6c9fc9d64633b5ee410def9c0210--86270d1c2a8548b8aaf9c5a862bc502c a25b7de1002f481f8905ba5e9413b864 RX(theta₃) 86270d1c2a8548b8aaf9c5a862bc502c--a25b7de1002f481f8905ba5e9413b864 11948a43408e46b5909ad0c96e0a1e37 RY(theta₇) a25b7de1002f481f8905ba5e9413b864--11948a43408e46b5909ad0c96e0a1e37 4eefb3784a40471db398a323d021a177 RX(theta₁₁) 11948a43408e46b5909ad0c96e0a1e37--4eefb3784a40471db398a323d021a177 23bb9b2fc6f0466d847c8c07025740ba X 4eefb3784a40471db398a323d021a177--23bb9b2fc6f0466d847c8c07025740ba 23bb9b2fc6f0466d847c8c07025740ba--b018adb1df334e6a8deaf58afaa6beba a0fad1d0e5a14b3abf4068ed8dba0ae8 23bb9b2fc6f0466d847c8c07025740ba--a0fad1d0e5a14b3abf4068ed8dba0ae8 ecb91557fb03427faa9ad45f3c9c561e RX(theta₁₅) a0fad1d0e5a14b3abf4068ed8dba0ae8--ecb91557fb03427faa9ad45f3c9c561e 50a03d44a9f343fb9e558f666390c504 RY(theta₁₉) ecb91557fb03427faa9ad45f3c9c561e--50a03d44a9f343fb9e558f666390c504 98aeea0e865949bcabf4901700f09271 RX(theta₂₃) 50a03d44a9f343fb9e558f666390c504--98aeea0e865949bcabf4901700f09271 37d7855dea50466d82cef13dbcde4058 X 98aeea0e865949bcabf4901700f09271--37d7855dea50466d82cef13dbcde4058 37d7855dea50466d82cef13dbcde4058--0abf807903654231a713a5137fdaa830 b2ab227f1aef4134b3c656ae1d80a027 37d7855dea50466d82cef13dbcde4058--b2ab227f1aef4134b3c656ae1d80a027 b2ab227f1aef4134b3c656ae1d80a027--05cc2aee09754e70bb64d5a876019be3
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, 0.+0.j, 1.+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.0886-0.1665j,  0.0552-0.0209j,  0.0795-0.0616j, -0.0848-0.4033j,
         -0.1008-0.1063j,  0.1614-0.3958j,  0.1703+0.1561j, -0.6405-0.3365j],
        [-0.3508+0.2872j,  0.1534-0.3051j,  0.1230-0.0179j,  0.2616+0.2750j,
         -0.1533+0.1843j, -0.2038+0.0606j,  0.4723-0.1386j, -0.3999+0.1165j]])

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