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.98170357+0.08698887j 0.        +0.j         0.1687232 +0.01495058j
 0.        +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_5d5137ea88c945609174d4b57b38e158 Circuit block cluster_44145603f5744d6bacb0b968ce4306bc Prep block 41811288d5e5457c8870e370b9087a4f 0 e546d14b248a4c7a929949c3526b5d91 41811288d5e5457c8870e370b9087a4f--e546d14b248a4c7a929949c3526b5d91 57775cc8925146dfacbd35e93865bcad 1 1c0a67be526349e5a199d0d899276cde RX(theta₀) e546d14b248a4c7a929949c3526b5d91--1c0a67be526349e5a199d0d899276cde e5d3d09977e249b587f7629fcece5d8c RY(theta₄) 1c0a67be526349e5a199d0d899276cde--e5d3d09977e249b587f7629fcece5d8c 6338565553f34ddfaebb0ccb2214f124 RX(theta₈) e5d3d09977e249b587f7629fcece5d8c--6338565553f34ddfaebb0ccb2214f124 5251d2075ff84fc9a1aa8d6bc55bbed1 6338565553f34ddfaebb0ccb2214f124--5251d2075ff84fc9a1aa8d6bc55bbed1 7ece6703b1574c00929f66e3826f9eca 5251d2075ff84fc9a1aa8d6bc55bbed1--7ece6703b1574c00929f66e3826f9eca 4f43f216b3804f08b7e2c8e184fd9948 RX(theta₁₂) 7ece6703b1574c00929f66e3826f9eca--4f43f216b3804f08b7e2c8e184fd9948 ef9c7a38f8ab46478dfe946b1e7ba4c5 RY(theta₁₆) 4f43f216b3804f08b7e2c8e184fd9948--ef9c7a38f8ab46478dfe946b1e7ba4c5 e9412bf881fd4ffb846ddd070bdc2b1e RX(theta₂₀) ef9c7a38f8ab46478dfe946b1e7ba4c5--e9412bf881fd4ffb846ddd070bdc2b1e 58e4909119da4121929d7258dd8303b3 e9412bf881fd4ffb846ddd070bdc2b1e--58e4909119da4121929d7258dd8303b3 7b03e0881a62469ea7b0f40b5fec6b58 58e4909119da4121929d7258dd8303b3--7b03e0881a62469ea7b0f40b5fec6b58 0cd8284f2bed46e797d14eda8f6fd484 7b03e0881a62469ea7b0f40b5fec6b58--0cd8284f2bed46e797d14eda8f6fd484 f4798ab4f6354eafb48c675a122c0417 36f14122809d4476af30bdbb712d8834 57775cc8925146dfacbd35e93865bcad--36f14122809d4476af30bdbb712d8834 67e0447692d04c71ac987a064c0df2a1 2 92e5e097ef3147e8936da67100bdc877 RX(theta₁) 36f14122809d4476af30bdbb712d8834--92e5e097ef3147e8936da67100bdc877 d22e1081aa60427ca71fbf666f3e0b0d RY(theta₅) 92e5e097ef3147e8936da67100bdc877--d22e1081aa60427ca71fbf666f3e0b0d 06ac25fa8db1461c9d8a0e706bd76934 RX(theta₉) d22e1081aa60427ca71fbf666f3e0b0d--06ac25fa8db1461c9d8a0e706bd76934 c4597c76ca1f484a8c331fd86cd0fd11 X 06ac25fa8db1461c9d8a0e706bd76934--c4597c76ca1f484a8c331fd86cd0fd11 c4597c76ca1f484a8c331fd86cd0fd11--5251d2075ff84fc9a1aa8d6bc55bbed1 6c458c6c0f024c7ca764a3cdb623d132 c4597c76ca1f484a8c331fd86cd0fd11--6c458c6c0f024c7ca764a3cdb623d132 05c5da3b85ef4a1f8d48461098089211 RX(theta₁₃) 6c458c6c0f024c7ca764a3cdb623d132--05c5da3b85ef4a1f8d48461098089211 b6a25877a3ee42b1926ccdfd55e654e1 RY(theta₁₇) 05c5da3b85ef4a1f8d48461098089211--b6a25877a3ee42b1926ccdfd55e654e1 ad1cb920ea244036b50e085e35112b7b RX(theta₂₁) b6a25877a3ee42b1926ccdfd55e654e1--ad1cb920ea244036b50e085e35112b7b a3e3262bbab9435688c040fa9b3d981f X ad1cb920ea244036b50e085e35112b7b--a3e3262bbab9435688c040fa9b3d981f a3e3262bbab9435688c040fa9b3d981f--58e4909119da4121929d7258dd8303b3 1bad337e8e55418bb015f886fce87070 a3e3262bbab9435688c040fa9b3d981f--1bad337e8e55418bb015f886fce87070 1bad337e8e55418bb015f886fce87070--f4798ab4f6354eafb48c675a122c0417 913bd6c6a3b64022bca9d70c4c97a190 e8b9892f7118475a9fad60d13af4e95f 67e0447692d04c71ac987a064c0df2a1--e8b9892f7118475a9fad60d13af4e95f a89eeca7738244d4b6ea58efe3ab1059 3 a0f7a3cad40f47ebbe3a5017763a3b51 RX(theta₂) e8b9892f7118475a9fad60d13af4e95f--a0f7a3cad40f47ebbe3a5017763a3b51 4ab5ecde90694bd39336e7352ece0fd1 RY(theta₆) a0f7a3cad40f47ebbe3a5017763a3b51--4ab5ecde90694bd39336e7352ece0fd1 08b6cf88a1504116a33a2cfd24da4dcc RX(theta₁₀) 4ab5ecde90694bd39336e7352ece0fd1--08b6cf88a1504116a33a2cfd24da4dcc f9d2ed3576cf40a1ac9df1fb09438748 08b6cf88a1504116a33a2cfd24da4dcc--f9d2ed3576cf40a1ac9df1fb09438748 e67453d656e24ec1aecec8e4484b9b05 X f9d2ed3576cf40a1ac9df1fb09438748--e67453d656e24ec1aecec8e4484b9b05 e67453d656e24ec1aecec8e4484b9b05--6c458c6c0f024c7ca764a3cdb623d132 3bbb139c8cfd4cfe8b42fa45e4807ff3 RX(theta₁₄) e67453d656e24ec1aecec8e4484b9b05--3bbb139c8cfd4cfe8b42fa45e4807ff3 130d65557d494ae5bf5876c55b3b79ce RY(theta₁₈) 3bbb139c8cfd4cfe8b42fa45e4807ff3--130d65557d494ae5bf5876c55b3b79ce 04c15e674abf41dba8b989d93169636d RX(theta₂₂) 130d65557d494ae5bf5876c55b3b79ce--04c15e674abf41dba8b989d93169636d 0f736a45a8794788b4676a83c3672ed0 04c15e674abf41dba8b989d93169636d--0f736a45a8794788b4676a83c3672ed0 e2beb9e61f824881a88387ebe46b1fc0 X 0f736a45a8794788b4676a83c3672ed0--e2beb9e61f824881a88387ebe46b1fc0 e2beb9e61f824881a88387ebe46b1fc0--1bad337e8e55418bb015f886fce87070 e2beb9e61f824881a88387ebe46b1fc0--913bd6c6a3b64022bca9d70c4c97a190 4b476347f82a47d98e266ca76b1b71de 8e460e875ac242938260b8bc4a7b4191 X a89eeca7738244d4b6ea58efe3ab1059--8e460e875ac242938260b8bc4a7b4191 53eff2090f564851bfd0d7b72d6bbde1 RX(theta₃) 8e460e875ac242938260b8bc4a7b4191--53eff2090f564851bfd0d7b72d6bbde1 c3df0817cf944cfcb8ddeaa7c34aacc9 RY(theta₇) 53eff2090f564851bfd0d7b72d6bbde1--c3df0817cf944cfcb8ddeaa7c34aacc9 b7ae042fcbba43669b1b965479081295 RX(theta₁₁) c3df0817cf944cfcb8ddeaa7c34aacc9--b7ae042fcbba43669b1b965479081295 0eb9219c84004489913d949a1ce3e038 X b7ae042fcbba43669b1b965479081295--0eb9219c84004489913d949a1ce3e038 0eb9219c84004489913d949a1ce3e038--f9d2ed3576cf40a1ac9df1fb09438748 f7cff9b28c1f45219fbd805fbf6bc487 0eb9219c84004489913d949a1ce3e038--f7cff9b28c1f45219fbd805fbf6bc487 651ecc4ce50a41678a1d3e06671e803e RX(theta₁₅) f7cff9b28c1f45219fbd805fbf6bc487--651ecc4ce50a41678a1d3e06671e803e 81ce5d3b4e1f4d3aaace34f9a3cdfc12 RY(theta₁₉) 651ecc4ce50a41678a1d3e06671e803e--81ce5d3b4e1f4d3aaace34f9a3cdfc12 071d42f81610422fb04469e648b3d4f1 RX(theta₂₃) 81ce5d3b4e1f4d3aaace34f9a3cdfc12--071d42f81610422fb04469e648b3d4f1 f0c284a65392415aae605215fe845898 X 071d42f81610422fb04469e648b3d4f1--f0c284a65392415aae605215fe845898 f0c284a65392415aae605215fe845898--0f736a45a8794788b4676a83c3672ed0 565f6bf77bf34a6f939d76cb68855efd f0c284a65392415aae605215fe845898--565f6bf77bf34a6f939d76cb68855efd 565f6bf77bf34a6f939d76cb68855efd--4b476347f82a47d98e266ca76b1b71de
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)
├── 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]])