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.94952497+0.j          0.        -0.05645406j -0.30802578+0.j
  0.        +0.01831369j]

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_18e344f5490c4261ade95796f0c09bb8 Circuit block cluster_03826e9360634e078c0e051d48080aa1 Prep block f0c732dc8eee4cfa9a11e4e480f1fe8b 0 3dbae2f7e8834e9ea45741d0307f94e5 f0c732dc8eee4cfa9a11e4e480f1fe8b--3dbae2f7e8834e9ea45741d0307f94e5 5224847b5b6e4c01b344d238046a7a4b 1 d46dce2d1eb64b8fb22e9f82c9d2630b RX(theta₀) 3dbae2f7e8834e9ea45741d0307f94e5--d46dce2d1eb64b8fb22e9f82c9d2630b b63f046386b049d8a86e043bcf09b457 RY(theta₄) d46dce2d1eb64b8fb22e9f82c9d2630b--b63f046386b049d8a86e043bcf09b457 8bb8c4141837469ca66f88179fbd7a93 RX(theta₈) b63f046386b049d8a86e043bcf09b457--8bb8c4141837469ca66f88179fbd7a93 d9db305898e44b3dadd9769a7f2de14b 8bb8c4141837469ca66f88179fbd7a93--d9db305898e44b3dadd9769a7f2de14b 6d1109fd14ab49a29a2c85fae518b619 d9db305898e44b3dadd9769a7f2de14b--6d1109fd14ab49a29a2c85fae518b619 30e78f4017024f9b81dfc4846eb77fa3 RX(theta₁₂) 6d1109fd14ab49a29a2c85fae518b619--30e78f4017024f9b81dfc4846eb77fa3 6a99063ab0c6482b95ea235ee9528fe4 RY(theta₁₆) 30e78f4017024f9b81dfc4846eb77fa3--6a99063ab0c6482b95ea235ee9528fe4 bc5205c8124c431f9495858cbc8def0b RX(theta₂₀) 6a99063ab0c6482b95ea235ee9528fe4--bc5205c8124c431f9495858cbc8def0b dae01062d9fa44359de947e8dbc23776 bc5205c8124c431f9495858cbc8def0b--dae01062d9fa44359de947e8dbc23776 9770962b0eb241afb458482b10a7347c dae01062d9fa44359de947e8dbc23776--9770962b0eb241afb458482b10a7347c 5891c9ed63f148e6bb71cb55c0207017 9770962b0eb241afb458482b10a7347c--5891c9ed63f148e6bb71cb55c0207017 a758d3f4aeeb454aaca30458330a4b51 0a8392ab951d486499637d730939fdaa 5224847b5b6e4c01b344d238046a7a4b--0a8392ab951d486499637d730939fdaa 5de67b97407f4603a822b751f789f82b 2 529b13691f2742dd9f61dab6b805b4a5 RX(theta₁) 0a8392ab951d486499637d730939fdaa--529b13691f2742dd9f61dab6b805b4a5 6c2e961678d34a8fbf94521689b96d2b RY(theta₅) 529b13691f2742dd9f61dab6b805b4a5--6c2e961678d34a8fbf94521689b96d2b 60c90fcc13664aa29460a131e506cdb8 RX(theta₉) 6c2e961678d34a8fbf94521689b96d2b--60c90fcc13664aa29460a131e506cdb8 5c27a5fe0fdc4131bf9f1dad4cb31973 X 60c90fcc13664aa29460a131e506cdb8--5c27a5fe0fdc4131bf9f1dad4cb31973 5c27a5fe0fdc4131bf9f1dad4cb31973--d9db305898e44b3dadd9769a7f2de14b caa967d58c3745c5b302321008590f44 5c27a5fe0fdc4131bf9f1dad4cb31973--caa967d58c3745c5b302321008590f44 fde2a49e5b1d44a8bf40e3ef8da6f314 RX(theta₁₃) caa967d58c3745c5b302321008590f44--fde2a49e5b1d44a8bf40e3ef8da6f314 1a0c7c367ae044c2ba21100e99813e16 RY(theta₁₇) fde2a49e5b1d44a8bf40e3ef8da6f314--1a0c7c367ae044c2ba21100e99813e16 942a3b04809d4031a4154c33b9961f35 RX(theta₂₁) 1a0c7c367ae044c2ba21100e99813e16--942a3b04809d4031a4154c33b9961f35 76871c3707cd48788712e6805c52d7ca X 942a3b04809d4031a4154c33b9961f35--76871c3707cd48788712e6805c52d7ca 76871c3707cd48788712e6805c52d7ca--dae01062d9fa44359de947e8dbc23776 336a85c074884492af69d0688e86a559 76871c3707cd48788712e6805c52d7ca--336a85c074884492af69d0688e86a559 336a85c074884492af69d0688e86a559--a758d3f4aeeb454aaca30458330a4b51 2a3a09842cd646d3a1dfb5288d8214be 92ce7cb9d2eb426a88b850a512736cb0 5de67b97407f4603a822b751f789f82b--92ce7cb9d2eb426a88b850a512736cb0 787ef060eec44c04b98d7dd4d97b0ebf 3 bc1b08e73a514e89adf713981ffc8aaa RX(theta₂) 92ce7cb9d2eb426a88b850a512736cb0--bc1b08e73a514e89adf713981ffc8aaa 2f321f1d562442cd9f4fad9005ce051c RY(theta₆) bc1b08e73a514e89adf713981ffc8aaa--2f321f1d562442cd9f4fad9005ce051c 5883404eb8d74bec83ffa976adf5aa87 RX(theta₁₀) 2f321f1d562442cd9f4fad9005ce051c--5883404eb8d74bec83ffa976adf5aa87 8437f6aa6be749a8856383653ed6532e 5883404eb8d74bec83ffa976adf5aa87--8437f6aa6be749a8856383653ed6532e b75d3f0f55cc4be18288ad4b40d9623e X 8437f6aa6be749a8856383653ed6532e--b75d3f0f55cc4be18288ad4b40d9623e b75d3f0f55cc4be18288ad4b40d9623e--caa967d58c3745c5b302321008590f44 04b6006441dc42f9a6a0f78883fe86fb RX(theta₁₄) b75d3f0f55cc4be18288ad4b40d9623e--04b6006441dc42f9a6a0f78883fe86fb 67cb231913334836872d18d9df5daf76 RY(theta₁₈) 04b6006441dc42f9a6a0f78883fe86fb--67cb231913334836872d18d9df5daf76 014a19df83904660b3aad751fe825213 RX(theta₂₂) 67cb231913334836872d18d9df5daf76--014a19df83904660b3aad751fe825213 d42fb2d245ec43bc893d27f7e05f91cc 014a19df83904660b3aad751fe825213--d42fb2d245ec43bc893d27f7e05f91cc 04097396190c4ae8899769c74f155b5e X d42fb2d245ec43bc893d27f7e05f91cc--04097396190c4ae8899769c74f155b5e 04097396190c4ae8899769c74f155b5e--336a85c074884492af69d0688e86a559 04097396190c4ae8899769c74f155b5e--2a3a09842cd646d3a1dfb5288d8214be 395247cf30f14ac9b71a8d716a4c2e6e dadabe79da9e4f06a3fce829af416f20 X 787ef060eec44c04b98d7dd4d97b0ebf--dadabe79da9e4f06a3fce829af416f20 1c31f00477d54edab29cd60c24604cb6 RX(theta₃) dadabe79da9e4f06a3fce829af416f20--1c31f00477d54edab29cd60c24604cb6 83c212998ff247a181256f491eb0340c RY(theta₇) 1c31f00477d54edab29cd60c24604cb6--83c212998ff247a181256f491eb0340c 43a463e712804e80b2670a4940f01ed6 RX(theta₁₁) 83c212998ff247a181256f491eb0340c--43a463e712804e80b2670a4940f01ed6 93f866e3e3b44f8aa99955920a6ec9c8 X 43a463e712804e80b2670a4940f01ed6--93f866e3e3b44f8aa99955920a6ec9c8 93f866e3e3b44f8aa99955920a6ec9c8--8437f6aa6be749a8856383653ed6532e 1dd57c74cfe8496cac3d366eee8fac90 93f866e3e3b44f8aa99955920a6ec9c8--1dd57c74cfe8496cac3d366eee8fac90 47f5066827e940948878dcb5dd60ef35 RX(theta₁₅) 1dd57c74cfe8496cac3d366eee8fac90--47f5066827e940948878dcb5dd60ef35 a383f5268b454ea4bc2c44e179a9c062 RY(theta₁₉) 47f5066827e940948878dcb5dd60ef35--a383f5268b454ea4bc2c44e179a9c062 97cb38251919435e9793c0ea1d312c02 RX(theta₂₃) a383f5268b454ea4bc2c44e179a9c062--97cb38251919435e9793c0ea1d312c02 de7859ca8ad3461dbb85487f88021034 X 97cb38251919435e9793c0ea1d312c02--de7859ca8ad3461dbb85487f88021034 de7859ca8ad3461dbb85487f88021034--d42fb2d245ec43bc893d27f7e05f91cc 811b3edc53a7469999686ff8aff28c14 de7859ca8ad3461dbb85487f88021034--811b3edc53a7469999686ff8aff28c14 811b3edc53a7469999686ff8aff28c14--395247cf30f14ac9b71a8d716a4c2e6e
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([[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, 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.4069-0.3345j,  0.0557-0.0508j,  0.1071-0.1038j, -0.3884-0.1071j,
          0.0203+0.4458j, -0.1258-0.1760j,  0.1835+0.1160j,  0.1922-0.4498j],
        [-0.2344-0.2973j, -0.0724+0.4345j, -0.1511+0.1684j, -0.2234-0.3202j,
          0.2596+0.3974j,  0.0339-0.4034j, -0.1082+0.0345j,  0.2104+0.1127j]])

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