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.89749838+0.j          0.        -0.13125579j  0.        -0.4166012j
 -0.06092637+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_e2803fae6898455d9cd1ae005f4b48fc Circuit block cluster_964b7db6102645d8af879e04c87b0fc9 Prep block a04a36afe12c4a4ba24593fee087d09b 0 f248ca72dd9546fbba936c968cac486d a04a36afe12c4a4ba24593fee087d09b--f248ca72dd9546fbba936c968cac486d c35622bbf737427f8cec94b4dd88a82b 1 75e6ddb0d7b7446d911f4911cce611e7 RX(theta₀) f248ca72dd9546fbba936c968cac486d--75e6ddb0d7b7446d911f4911cce611e7 aab525261d364c8b8f6d1877e6440307 RY(theta₄) 75e6ddb0d7b7446d911f4911cce611e7--aab525261d364c8b8f6d1877e6440307 bf99ed9a58384af8ba1ca3f8d1bdbf97 RX(theta₈) aab525261d364c8b8f6d1877e6440307--bf99ed9a58384af8ba1ca3f8d1bdbf97 8f654ff6792541e8b2370801224633e4 bf99ed9a58384af8ba1ca3f8d1bdbf97--8f654ff6792541e8b2370801224633e4 ffe5a9b02eca4fb394612a98e58cdb0a 8f654ff6792541e8b2370801224633e4--ffe5a9b02eca4fb394612a98e58cdb0a f4e13f7dbdd7418eb181d010bf989346 RX(theta₁₂) ffe5a9b02eca4fb394612a98e58cdb0a--f4e13f7dbdd7418eb181d010bf989346 37881bcc6de54448849d5e6e4b9ec4f1 RY(theta₁₆) f4e13f7dbdd7418eb181d010bf989346--37881bcc6de54448849d5e6e4b9ec4f1 b6fba4394e59473b8c51351b2906cb60 RX(theta₂₀) 37881bcc6de54448849d5e6e4b9ec4f1--b6fba4394e59473b8c51351b2906cb60 1bbad0dd201341a08cdcfebb5e594d88 b6fba4394e59473b8c51351b2906cb60--1bbad0dd201341a08cdcfebb5e594d88 bf7585315368476981c8113b454fa531 1bbad0dd201341a08cdcfebb5e594d88--bf7585315368476981c8113b454fa531 6f597ba0776646c29b4806f42c5544f6 bf7585315368476981c8113b454fa531--6f597ba0776646c29b4806f42c5544f6 a00dab95ad104552991c8c1cb9c46b96 6194579f32a14c9f9df30b172543f5fa c35622bbf737427f8cec94b4dd88a82b--6194579f32a14c9f9df30b172543f5fa 279edcdb1e8241ffab6a47df370437a3 2 e8eec732b8754e4b9878d180a5d23fa3 RX(theta₁) 6194579f32a14c9f9df30b172543f5fa--e8eec732b8754e4b9878d180a5d23fa3 80955f3c7b0945ecbbcff5ad9b5a4044 RY(theta₅) e8eec732b8754e4b9878d180a5d23fa3--80955f3c7b0945ecbbcff5ad9b5a4044 b82c4ba608f545b482813cd0601af985 RX(theta₉) 80955f3c7b0945ecbbcff5ad9b5a4044--b82c4ba608f545b482813cd0601af985 1815421e7c7641328024903cac061150 X b82c4ba608f545b482813cd0601af985--1815421e7c7641328024903cac061150 1815421e7c7641328024903cac061150--8f654ff6792541e8b2370801224633e4 362ac87efca244469a8fe85ad220689b 1815421e7c7641328024903cac061150--362ac87efca244469a8fe85ad220689b a73706b89d08476fb96dd909bb371fa3 RX(theta₁₃) 362ac87efca244469a8fe85ad220689b--a73706b89d08476fb96dd909bb371fa3 6feda130ebf54fa28b2eca7f562a9af4 RY(theta₁₇) a73706b89d08476fb96dd909bb371fa3--6feda130ebf54fa28b2eca7f562a9af4 acef2f7dfd2547398fddfa555460738f RX(theta₂₁) 6feda130ebf54fa28b2eca7f562a9af4--acef2f7dfd2547398fddfa555460738f fbca7055b3824b4e8dda029d060b9787 X acef2f7dfd2547398fddfa555460738f--fbca7055b3824b4e8dda029d060b9787 fbca7055b3824b4e8dda029d060b9787--1bbad0dd201341a08cdcfebb5e594d88 2838ee50ec524f75babd4217fd280710 fbca7055b3824b4e8dda029d060b9787--2838ee50ec524f75babd4217fd280710 2838ee50ec524f75babd4217fd280710--a00dab95ad104552991c8c1cb9c46b96 c8440ae402c54665a97220ee72660b6e 4ba6e41d28144de3bede8a779a9241d0 279edcdb1e8241ffab6a47df370437a3--4ba6e41d28144de3bede8a779a9241d0 2d48cc40b69f40968993f0e1403e905c 3 5c58f3473fe542e3a2377fe871e61f00 RX(theta₂) 4ba6e41d28144de3bede8a779a9241d0--5c58f3473fe542e3a2377fe871e61f00 6dcfcc4f59ce42069bc828e328c4f224 RY(theta₆) 5c58f3473fe542e3a2377fe871e61f00--6dcfcc4f59ce42069bc828e328c4f224 339c97d134244db7ab3a022fbfada8ec RX(theta₁₀) 6dcfcc4f59ce42069bc828e328c4f224--339c97d134244db7ab3a022fbfada8ec 0b551fb04a8a4d398762b59036f01f2e 339c97d134244db7ab3a022fbfada8ec--0b551fb04a8a4d398762b59036f01f2e 8d5dd138a1b44e47b6f1351b9300ec09 X 0b551fb04a8a4d398762b59036f01f2e--8d5dd138a1b44e47b6f1351b9300ec09 8d5dd138a1b44e47b6f1351b9300ec09--362ac87efca244469a8fe85ad220689b a94f932a8e3c458fb3f1130588881afa RX(theta₁₄) 8d5dd138a1b44e47b6f1351b9300ec09--a94f932a8e3c458fb3f1130588881afa 9829cc4d112c4f549fdcf7dfa63c8b29 RY(theta₁₈) a94f932a8e3c458fb3f1130588881afa--9829cc4d112c4f549fdcf7dfa63c8b29 dc77ca294bd64a3baa87377ab4d16868 RX(theta₂₂) 9829cc4d112c4f549fdcf7dfa63c8b29--dc77ca294bd64a3baa87377ab4d16868 6ab7b750f8f64123b406710de53312f9 dc77ca294bd64a3baa87377ab4d16868--6ab7b750f8f64123b406710de53312f9 67bb26e979eb473ea5917a2d5ac03738 X 6ab7b750f8f64123b406710de53312f9--67bb26e979eb473ea5917a2d5ac03738 67bb26e979eb473ea5917a2d5ac03738--2838ee50ec524f75babd4217fd280710 67bb26e979eb473ea5917a2d5ac03738--c8440ae402c54665a97220ee72660b6e 64775ad8d61842fe87a0c85082a373c2 6c0cc88bc6834b578fddf8cf573a03e9 X 2d48cc40b69f40968993f0e1403e905c--6c0cc88bc6834b578fddf8cf573a03e9 117bff62d3ff4c75b45e19c867f5e3af RX(theta₃) 6c0cc88bc6834b578fddf8cf573a03e9--117bff62d3ff4c75b45e19c867f5e3af 1c774a5413fe499a8b5eb02b2a7881c6 RY(theta₇) 117bff62d3ff4c75b45e19c867f5e3af--1c774a5413fe499a8b5eb02b2a7881c6 c378b8c4e4744ac89c8c368ff419235f RX(theta₁₁) 1c774a5413fe499a8b5eb02b2a7881c6--c378b8c4e4744ac89c8c368ff419235f 939126a168cc4504b055911983d34b89 X c378b8c4e4744ac89c8c368ff419235f--939126a168cc4504b055911983d34b89 939126a168cc4504b055911983d34b89--0b551fb04a8a4d398762b59036f01f2e 7724d4318f6a42a9ba65a45a2db005bd 939126a168cc4504b055911983d34b89--7724d4318f6a42a9ba65a45a2db005bd 0acd742827a6418498fcdd51ef273aec RX(theta₁₅) 7724d4318f6a42a9ba65a45a2db005bd--0acd742827a6418498fcdd51ef273aec 73fae0447b854d41b9b0ea501813e88e RY(theta₁₉) 0acd742827a6418498fcdd51ef273aec--73fae0447b854d41b9b0ea501813e88e e66fc9b85fb4486b85070202b803db54 RX(theta₂₃) 73fae0447b854d41b9b0ea501813e88e--e66fc9b85fb4486b85070202b803db54 2c059cddc32e4fdbb836acc7d3b4e79d X e66fc9b85fb4486b85070202b803db54--2c059cddc32e4fdbb836acc7d3b4e79d 2c059cddc32e4fdbb836acc7d3b4e79d--6ab7b750f8f64123b406710de53312f9 e8d447887d314b4e9bdd8bea85ee3338 2c059cddc32e4fdbb836acc7d3b4e79d--e8d447887d314b4e9bdd8bea85ee3338 e8d447887d314b4e9bdd8bea85ee3338--64775ad8d61842fe87a0c85082a373c2
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, 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, 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.3917+0.3284j,  0.2472-0.2105j,  0.0093-0.0121j,  0.0861+0.2614j,
         -0.3026+0.4079j, -0.0945+0.2842j,  0.1811+0.1354j, -0.3108-0.2488j],
        [-0.0030+0.1188j,  0.6237+0.3131j, -0.0163-0.1548j,  0.2488+0.0077j,
          0.1992-0.0109j,  0.2398+0.3233j, -0.0816-0.1897j,  0.3764-0.1628j]])

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