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.95906007+0.28320273j 0.        +0.j         0.        +0.j
 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_88edb20c2d09423282a10c4dca66ab90 Circuit block cluster_d5fc1a366de34314b93e58878e0f5877 Prep block 8365e1d6af6e4527a056b0754602b5b2 0 04a90a58c4f5435fa92f357a791abc7d 8365e1d6af6e4527a056b0754602b5b2--04a90a58c4f5435fa92f357a791abc7d 3e026bb4e83f4fbe9a4652a009780935 1 0a92954537db4449a17b923f90a157b8 RX(theta₀) 04a90a58c4f5435fa92f357a791abc7d--0a92954537db4449a17b923f90a157b8 eeee0eca30b14a89ba19353179e64037 RY(theta₄) 0a92954537db4449a17b923f90a157b8--eeee0eca30b14a89ba19353179e64037 3e3c19293d724a95b2772fba828e7b62 RX(theta₈) eeee0eca30b14a89ba19353179e64037--3e3c19293d724a95b2772fba828e7b62 2460107fb237423d89af67c33890faf1 3e3c19293d724a95b2772fba828e7b62--2460107fb237423d89af67c33890faf1 573c61eb2317454e9ae25f5c688166a4 2460107fb237423d89af67c33890faf1--573c61eb2317454e9ae25f5c688166a4 282ab59406e74276a21b1d9043cdb635 RX(theta₁₂) 573c61eb2317454e9ae25f5c688166a4--282ab59406e74276a21b1d9043cdb635 9e1720acecd449c19400844ee1dae4bd RY(theta₁₆) 282ab59406e74276a21b1d9043cdb635--9e1720acecd449c19400844ee1dae4bd 31f1862e71a046318f0f39d03f190078 RX(theta₂₀) 9e1720acecd449c19400844ee1dae4bd--31f1862e71a046318f0f39d03f190078 58981d93abce4cc7a078da61ef456d70 31f1862e71a046318f0f39d03f190078--58981d93abce4cc7a078da61ef456d70 4a62e9e915ee429eb981c867aa0ac4f3 58981d93abce4cc7a078da61ef456d70--4a62e9e915ee429eb981c867aa0ac4f3 d5814ca912ac47a4bf54b37e64320aa1 4a62e9e915ee429eb981c867aa0ac4f3--d5814ca912ac47a4bf54b37e64320aa1 20c6a5b3f6e548b29c39131ae7b8175f 8742ab7fe4d547a48aa0aa22eb44d8be 3e026bb4e83f4fbe9a4652a009780935--8742ab7fe4d547a48aa0aa22eb44d8be 452930b78a6e421c8c24d159d221ac60 2 4c6f0a7605c045d4b1d14f73bbf5bd22 RX(theta₁) 8742ab7fe4d547a48aa0aa22eb44d8be--4c6f0a7605c045d4b1d14f73bbf5bd22 523745abdfd640c0b3a3570746811dfe RY(theta₅) 4c6f0a7605c045d4b1d14f73bbf5bd22--523745abdfd640c0b3a3570746811dfe 0dbf0aa3527f4c3a8997e123b92d4de0 RX(theta₉) 523745abdfd640c0b3a3570746811dfe--0dbf0aa3527f4c3a8997e123b92d4de0 c792e988497a41ebb60ca19375177b67 X 0dbf0aa3527f4c3a8997e123b92d4de0--c792e988497a41ebb60ca19375177b67 c792e988497a41ebb60ca19375177b67--2460107fb237423d89af67c33890faf1 092c53943c4d43ecb4ffcf3b58465488 c792e988497a41ebb60ca19375177b67--092c53943c4d43ecb4ffcf3b58465488 6f4aa08f2f82428296ea8fd7a7fc6501 RX(theta₁₃) 092c53943c4d43ecb4ffcf3b58465488--6f4aa08f2f82428296ea8fd7a7fc6501 8292c3a5b0fd424aabf353f2010835ec RY(theta₁₇) 6f4aa08f2f82428296ea8fd7a7fc6501--8292c3a5b0fd424aabf353f2010835ec 66a100647ceb4e34af1536c1d8a2106e RX(theta₂₁) 8292c3a5b0fd424aabf353f2010835ec--66a100647ceb4e34af1536c1d8a2106e 815b2b2f52f24062bcb8bfddc302fcca X 66a100647ceb4e34af1536c1d8a2106e--815b2b2f52f24062bcb8bfddc302fcca 815b2b2f52f24062bcb8bfddc302fcca--58981d93abce4cc7a078da61ef456d70 6851e8ac7bdf4af88d795b53cbaf25cd 815b2b2f52f24062bcb8bfddc302fcca--6851e8ac7bdf4af88d795b53cbaf25cd 6851e8ac7bdf4af88d795b53cbaf25cd--20c6a5b3f6e548b29c39131ae7b8175f ecd823085b654e87810f909f4ed18dc5 5456698631b44cd99f8a7ae987d50293 452930b78a6e421c8c24d159d221ac60--5456698631b44cd99f8a7ae987d50293 56019214a71045349087220adec6b25c 3 b08e1ec2fa4d4a2bbaf59b39b95ab0de RX(theta₂) 5456698631b44cd99f8a7ae987d50293--b08e1ec2fa4d4a2bbaf59b39b95ab0de 54889f73bc244d30800c9fb5cf702eda RY(theta₆) b08e1ec2fa4d4a2bbaf59b39b95ab0de--54889f73bc244d30800c9fb5cf702eda dca265a130ed4ac79f93e26f367f4dc9 RX(theta₁₀) 54889f73bc244d30800c9fb5cf702eda--dca265a130ed4ac79f93e26f367f4dc9 f59e2b501c7d4fba9c72e43db1e96753 dca265a130ed4ac79f93e26f367f4dc9--f59e2b501c7d4fba9c72e43db1e96753 9934396648784ff784e7e6d687dbd0d0 X f59e2b501c7d4fba9c72e43db1e96753--9934396648784ff784e7e6d687dbd0d0 9934396648784ff784e7e6d687dbd0d0--092c53943c4d43ecb4ffcf3b58465488 dcf30b64f58e43a8b463fd1719cf7b20 RX(theta₁₄) 9934396648784ff784e7e6d687dbd0d0--dcf30b64f58e43a8b463fd1719cf7b20 480d688e7e10456ab957fcd497672d18 RY(theta₁₈) dcf30b64f58e43a8b463fd1719cf7b20--480d688e7e10456ab957fcd497672d18 b008f68ea24c4d238642464bd6176321 RX(theta₂₂) 480d688e7e10456ab957fcd497672d18--b008f68ea24c4d238642464bd6176321 37c6264aba9942fd8ce9c954b8bb3437 b008f68ea24c4d238642464bd6176321--37c6264aba9942fd8ce9c954b8bb3437 12036dbeb778449cbb6a53efdd045e40 X 37c6264aba9942fd8ce9c954b8bb3437--12036dbeb778449cbb6a53efdd045e40 12036dbeb778449cbb6a53efdd045e40--6851e8ac7bdf4af88d795b53cbaf25cd 12036dbeb778449cbb6a53efdd045e40--ecd823085b654e87810f909f4ed18dc5 7cd58e8b790d4e44ba2764effe6fefea 9fa97f9a9adc42ee8d25097139a46c07 X 56019214a71045349087220adec6b25c--9fa97f9a9adc42ee8d25097139a46c07 8ca221f817574054ae504a62994076a4 RX(theta₃) 9fa97f9a9adc42ee8d25097139a46c07--8ca221f817574054ae504a62994076a4 117a6a98d20343d6855aca00b6191c55 RY(theta₇) 8ca221f817574054ae504a62994076a4--117a6a98d20343d6855aca00b6191c55 a9bf44ae986f4eb8a403c9aa5b2411a0 RX(theta₁₁) 117a6a98d20343d6855aca00b6191c55--a9bf44ae986f4eb8a403c9aa5b2411a0 4bb42067adbd4598a29dc0fa39f36d2e X a9bf44ae986f4eb8a403c9aa5b2411a0--4bb42067adbd4598a29dc0fa39f36d2e 4bb42067adbd4598a29dc0fa39f36d2e--f59e2b501c7d4fba9c72e43db1e96753 489385547e704d2f853fc778c10b1cd4 4bb42067adbd4598a29dc0fa39f36d2e--489385547e704d2f853fc778c10b1cd4 ea0f261c12db46bc88a973ffddc00fa6 RX(theta₁₅) 489385547e704d2f853fc778c10b1cd4--ea0f261c12db46bc88a973ffddc00fa6 a87e3b9fa10e4b09b385ad1780eafd44 RY(theta₁₉) ea0f261c12db46bc88a973ffddc00fa6--a87e3b9fa10e4b09b385ad1780eafd44 ea5a70867ae54cadbb3654786dc88829 RX(theta₂₃) a87e3b9fa10e4b09b385ad1780eafd44--ea5a70867ae54cadbb3654786dc88829 14a06f8f578f4acca4e0349f7676d9d5 X ea5a70867ae54cadbb3654786dc88829--14a06f8f578f4acca4e0349f7676d9d5 14a06f8f578f4acca4e0349f7676d9d5--37c6264aba9942fd8ce9c954b8bb3437 33e9eacafd734cbb87198c7294a682cc 14a06f8f578f4acca4e0349f7676d9d5--33e9eacafd734cbb87198c7294a682cc 33e9eacafd734cbb87198c7294a682cc--7cd58e8b790d4e44ba2764effe6fefea
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, 0.+0.j, 0.+0.j, 0.+0.j, 1.+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.1979+0.1218j,  0.3503-0.3097j, -0.2027+0.2565j,  0.2727-0.3882j,
          0.3138+0.4586j,  0.2025-0.1360j,  0.1061+0.0889j,  0.0225-0.0858j],
        [ 0.5372+0.3381j,  0.3074-0.1143j, -0.2248+0.0703j, -0.0898-0.2938j,
         -0.0896-0.1091j, -0.1593-0.4118j,  0.2188+0.1255j, -0.2026+0.1417j]])

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

Density matrices conversion

It is also possible to obtain density matrices from statevectors. They can be passed as inputs to quantum programs performing density matrix based operations such as noisy simulations, when the backend allows such as PyQTorch.

from qadence import product_state, density_mat

init_state = product_state("10")
init_density_matrix = density_mat(init_state)

final_density_matrix = run(CNOT(0, 1), state=init_density_matrix)
Initial = DensityMatrix([[[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, 0.+0.j],
                [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]]])
Final = DensityMatrix([[[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, 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]])