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.64514427+0.70981379j -0.20924619+0.19018224j  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_0262a26380cc46c7880bebdab792ce43 Circuit block cluster_5c988ce19451420f8038cd76a7c864ad Prep block 965fc9546493403abf342ec68590f433 0 cef9bbfc48034a679167c333a1d1f161 965fc9546493403abf342ec68590f433--cef9bbfc48034a679167c333a1d1f161 9c76f2db3e9447dbaeb3de04a309b5b3 1 f3d07d66d1444b07ae5e7e46389f8173 RX(theta₀) cef9bbfc48034a679167c333a1d1f161--f3d07d66d1444b07ae5e7e46389f8173 cd28b27898304d6ea4ef872f8479a383 RY(theta₄) f3d07d66d1444b07ae5e7e46389f8173--cd28b27898304d6ea4ef872f8479a383 1b001af3cc0e4d49ae9f72699211ea5c RX(theta₈) cd28b27898304d6ea4ef872f8479a383--1b001af3cc0e4d49ae9f72699211ea5c f581baac90b04740b939aec6086d7242 1b001af3cc0e4d49ae9f72699211ea5c--f581baac90b04740b939aec6086d7242 6323847584ba484f9ae4296c33a76936 f581baac90b04740b939aec6086d7242--6323847584ba484f9ae4296c33a76936 a233eb9bfda64b1f9f6243367c6de050 RX(theta₁₂) 6323847584ba484f9ae4296c33a76936--a233eb9bfda64b1f9f6243367c6de050 85e58d1a218144d090dcc9142c87bcb3 RY(theta₁₆) a233eb9bfda64b1f9f6243367c6de050--85e58d1a218144d090dcc9142c87bcb3 f8c4d3fd31fc48e5bb55b0da5bc5dbb1 RX(theta₂₀) 85e58d1a218144d090dcc9142c87bcb3--f8c4d3fd31fc48e5bb55b0da5bc5dbb1 694ab9cfdd0d4d758c9336dd10bc4cdb f8c4d3fd31fc48e5bb55b0da5bc5dbb1--694ab9cfdd0d4d758c9336dd10bc4cdb a54ba4ccd86d46bc84ff15099863d4da 694ab9cfdd0d4d758c9336dd10bc4cdb--a54ba4ccd86d46bc84ff15099863d4da 2fd3ae3eca454a2cb26db04c88e36879 a54ba4ccd86d46bc84ff15099863d4da--2fd3ae3eca454a2cb26db04c88e36879 7f168154be8e4ae2bb5c070991b1cd0c 6979535ad6ee4cb8b42605e41c71608e 9c76f2db3e9447dbaeb3de04a309b5b3--6979535ad6ee4cb8b42605e41c71608e 291b95f5553044448d482e01b2338b31 2 349c262069bd4bbe9fe4526b278aba33 RX(theta₁) 6979535ad6ee4cb8b42605e41c71608e--349c262069bd4bbe9fe4526b278aba33 963e3763093c4d3093c6ea90e4365c1b RY(theta₅) 349c262069bd4bbe9fe4526b278aba33--963e3763093c4d3093c6ea90e4365c1b 30618c9d8e65456d818047388974207e RX(theta₉) 963e3763093c4d3093c6ea90e4365c1b--30618c9d8e65456d818047388974207e 6b25ba3c4b574124b8ae4777b035eabf X 30618c9d8e65456d818047388974207e--6b25ba3c4b574124b8ae4777b035eabf 6b25ba3c4b574124b8ae4777b035eabf--f581baac90b04740b939aec6086d7242 589f4adfb7ec4672a67156742943bae3 6b25ba3c4b574124b8ae4777b035eabf--589f4adfb7ec4672a67156742943bae3 991ef98bd2064cb3b35881aa200898a8 RX(theta₁₃) 589f4adfb7ec4672a67156742943bae3--991ef98bd2064cb3b35881aa200898a8 76e4767a24a6426bb1c1e971d4805a22 RY(theta₁₇) 991ef98bd2064cb3b35881aa200898a8--76e4767a24a6426bb1c1e971d4805a22 92d592c0d61442638840cb4d27c21281 RX(theta₂₁) 76e4767a24a6426bb1c1e971d4805a22--92d592c0d61442638840cb4d27c21281 523b2bc1b3c741e387ce56ce537cac7d X 92d592c0d61442638840cb4d27c21281--523b2bc1b3c741e387ce56ce537cac7d 523b2bc1b3c741e387ce56ce537cac7d--694ab9cfdd0d4d758c9336dd10bc4cdb d5181bf61ea7495da4f121b387826005 523b2bc1b3c741e387ce56ce537cac7d--d5181bf61ea7495da4f121b387826005 d5181bf61ea7495da4f121b387826005--7f168154be8e4ae2bb5c070991b1cd0c 51f2b5fb4d6542048817f023fe2eab14 db5daf24071a455f982ede19e1d9f30c 291b95f5553044448d482e01b2338b31--db5daf24071a455f982ede19e1d9f30c e6fed0f4ea4548d4b0f519ad736e70a0 3 08eac6f9372643adafd8f4b975cc9244 RX(theta₂) db5daf24071a455f982ede19e1d9f30c--08eac6f9372643adafd8f4b975cc9244 78929fb76ffb4fd89a1b0aca542f5f41 RY(theta₆) 08eac6f9372643adafd8f4b975cc9244--78929fb76ffb4fd89a1b0aca542f5f41 c7983985089d4ade8329e623499a9356 RX(theta₁₀) 78929fb76ffb4fd89a1b0aca542f5f41--c7983985089d4ade8329e623499a9356 1362c90afc0b472c9ac6c1fbcaff8bec c7983985089d4ade8329e623499a9356--1362c90afc0b472c9ac6c1fbcaff8bec cd3d0659dbd348e6a1f2b4a78a3b0b7d X 1362c90afc0b472c9ac6c1fbcaff8bec--cd3d0659dbd348e6a1f2b4a78a3b0b7d cd3d0659dbd348e6a1f2b4a78a3b0b7d--589f4adfb7ec4672a67156742943bae3 4f503255da42420aa0f1ca7f85cd51e7 RX(theta₁₄) cd3d0659dbd348e6a1f2b4a78a3b0b7d--4f503255da42420aa0f1ca7f85cd51e7 709d03c26fab41ceb95aaf09fd5b3b65 RY(theta₁₈) 4f503255da42420aa0f1ca7f85cd51e7--709d03c26fab41ceb95aaf09fd5b3b65 1fd462da7b6f4507a8111de5d7f63788 RX(theta₂₂) 709d03c26fab41ceb95aaf09fd5b3b65--1fd462da7b6f4507a8111de5d7f63788 dc3b73bb4bec4cae9fca15c22a63cf91 1fd462da7b6f4507a8111de5d7f63788--dc3b73bb4bec4cae9fca15c22a63cf91 c4dd7e67620e48569c62ab9768c7aede X dc3b73bb4bec4cae9fca15c22a63cf91--c4dd7e67620e48569c62ab9768c7aede c4dd7e67620e48569c62ab9768c7aede--d5181bf61ea7495da4f121b387826005 c4dd7e67620e48569c62ab9768c7aede--51f2b5fb4d6542048817f023fe2eab14 21210245c9b64d458db5d3aced626ffc b72e49b981964701ad8c0bec2cf8c6be X e6fed0f4ea4548d4b0f519ad736e70a0--b72e49b981964701ad8c0bec2cf8c6be 665bb1420f694a9b9a6465aa30c7e184 RX(theta₃) b72e49b981964701ad8c0bec2cf8c6be--665bb1420f694a9b9a6465aa30c7e184 a68238faf1b74db8855836abde648d3c RY(theta₇) 665bb1420f694a9b9a6465aa30c7e184--a68238faf1b74db8855836abde648d3c d4dd419afc3e464e97929ac09c33a3f7 RX(theta₁₁) a68238faf1b74db8855836abde648d3c--d4dd419afc3e464e97929ac09c33a3f7 fc44057c79f94fdeaa4dd09e33e832d0 X d4dd419afc3e464e97929ac09c33a3f7--fc44057c79f94fdeaa4dd09e33e832d0 fc44057c79f94fdeaa4dd09e33e832d0--1362c90afc0b472c9ac6c1fbcaff8bec ebe54aee18ec4c60b0f4bb4a0d29d09f fc44057c79f94fdeaa4dd09e33e832d0--ebe54aee18ec4c60b0f4bb4a0d29d09f 1f8b7d11d4df4aa393172427096cc4cb RX(theta₁₅) ebe54aee18ec4c60b0f4bb4a0d29d09f--1f8b7d11d4df4aa393172427096cc4cb 10acec576c534aa19fa9b48faf2f6c1c RY(theta₁₉) 1f8b7d11d4df4aa393172427096cc4cb--10acec576c534aa19fa9b48faf2f6c1c efd9cf6b31da4135830cb56064c29644 RX(theta₂₃) 10acec576c534aa19fa9b48faf2f6c1c--efd9cf6b31da4135830cb56064c29644 fadd39cee5c74f90aa200a2181a7cf15 X efd9cf6b31da4135830cb56064c29644--fadd39cee5c74f90aa200a2181a7cf15 fadd39cee5c74f90aa200a2181a7cf15--dc3b73bb4bec4cae9fca15c22a63cf91 c242c73acfe647f8a63908e0737c26d9 fadd39cee5c74f90aa200a2181a7cf15--c242c73acfe647f8a63908e0737c26d9 c242c73acfe647f8a63908e0737c26d9--21210245c9b64d458db5d3aced626ffc
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],
        [0.+0.j, 0.+0.j, 0.+0.j, 1.+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.2045-0.2269j,  0.1438+0.5498j, -0.2988-0.1390j,  0.4756-0.2455j,
         -0.1202-0.2038j,  0.0159-0.2576j,  0.1665+0.0168j, -0.1088+0.1620j],
        [-0.2920-0.0203j,  0.0644+0.0055j, -0.1784-0.1456j, -0.3402+0.0117j,
          0.3525+0.4059j, -0.4295-0.0742j,  0.0256-0.3383j, -0.3828-0.0263j]])

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