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.21959765+0.97559053j 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_b2a6c26dbdf64fd4b00e5380f93930c2 Circuit block cluster_d8e287e3976b4f438f18262ef93e45d5 Prep block 820d31832a9d4dbaa66f146d8b403984 0 11d8281b3b214d3abd66b8d29f311a56 820d31832a9d4dbaa66f146d8b403984--11d8281b3b214d3abd66b8d29f311a56 eb706d54fffa41ee9add246cee12959d 1 4ebfe6b7664f48939c3626a36f4d166b RX(theta₀) 11d8281b3b214d3abd66b8d29f311a56--4ebfe6b7664f48939c3626a36f4d166b 9221bb8a2f5f43309f2fd47d52e3822d RY(theta₄) 4ebfe6b7664f48939c3626a36f4d166b--9221bb8a2f5f43309f2fd47d52e3822d fda12a8edc334e29bcf83ddc0d7bb22c RX(theta₈) 9221bb8a2f5f43309f2fd47d52e3822d--fda12a8edc334e29bcf83ddc0d7bb22c d94f4ea30c624235bccf5b13f7a8caf0 fda12a8edc334e29bcf83ddc0d7bb22c--d94f4ea30c624235bccf5b13f7a8caf0 d47f0bd5374e4930bb227d60034aa7e0 d94f4ea30c624235bccf5b13f7a8caf0--d47f0bd5374e4930bb227d60034aa7e0 ed3260f1ccd34ecb9fd3ec2ad3a02050 RX(theta₁₂) d47f0bd5374e4930bb227d60034aa7e0--ed3260f1ccd34ecb9fd3ec2ad3a02050 759f0f9c50ae4e31aea38e0b7f01052c RY(theta₁₆) ed3260f1ccd34ecb9fd3ec2ad3a02050--759f0f9c50ae4e31aea38e0b7f01052c 8942fab441354249abe85742f1ed7454 RX(theta₂₀) 759f0f9c50ae4e31aea38e0b7f01052c--8942fab441354249abe85742f1ed7454 d0acce4b19d64b4abe3b7b77fd4723d4 8942fab441354249abe85742f1ed7454--d0acce4b19d64b4abe3b7b77fd4723d4 472b3ff838844ffa997717a553ecf0e2 d0acce4b19d64b4abe3b7b77fd4723d4--472b3ff838844ffa997717a553ecf0e2 0d6c771d7d5b430e811f9e65e9444d6c 472b3ff838844ffa997717a553ecf0e2--0d6c771d7d5b430e811f9e65e9444d6c d8bedd372c234d0ba6c97ef82f7aa375 49a521e7ef584d4a8aa5ccabd5c7b716 eb706d54fffa41ee9add246cee12959d--49a521e7ef584d4a8aa5ccabd5c7b716 c2ae9ce2f50f47d3886257ac8b91a14f 2 1e7951661dca41959214b137634c074c RX(theta₁) 49a521e7ef584d4a8aa5ccabd5c7b716--1e7951661dca41959214b137634c074c a46e750a9dbf4dceaaee95606936ca85 RY(theta₅) 1e7951661dca41959214b137634c074c--a46e750a9dbf4dceaaee95606936ca85 7c5636755ce94dfd8430e78df1bac95a RX(theta₉) a46e750a9dbf4dceaaee95606936ca85--7c5636755ce94dfd8430e78df1bac95a 73716b629f004146ab9f84c204aea2b6 X 7c5636755ce94dfd8430e78df1bac95a--73716b629f004146ab9f84c204aea2b6 73716b629f004146ab9f84c204aea2b6--d94f4ea30c624235bccf5b13f7a8caf0 e3d55fffe1ab4184868a0e54b5b502d9 73716b629f004146ab9f84c204aea2b6--e3d55fffe1ab4184868a0e54b5b502d9 b19400da4f3f4fa4a2d4ca2de461d9d3 RX(theta₁₃) e3d55fffe1ab4184868a0e54b5b502d9--b19400da4f3f4fa4a2d4ca2de461d9d3 14735dfcf5b5418b978f39dc9b407e3e RY(theta₁₇) b19400da4f3f4fa4a2d4ca2de461d9d3--14735dfcf5b5418b978f39dc9b407e3e 49ea3879139a4951af7144146bac57fd RX(theta₂₁) 14735dfcf5b5418b978f39dc9b407e3e--49ea3879139a4951af7144146bac57fd eeced7fd594a4d30a8312e53e2ebf126 X 49ea3879139a4951af7144146bac57fd--eeced7fd594a4d30a8312e53e2ebf126 eeced7fd594a4d30a8312e53e2ebf126--d0acce4b19d64b4abe3b7b77fd4723d4 f1c81b95af444298b8d0a88158696cb5 eeced7fd594a4d30a8312e53e2ebf126--f1c81b95af444298b8d0a88158696cb5 f1c81b95af444298b8d0a88158696cb5--d8bedd372c234d0ba6c97ef82f7aa375 786df64f6c20453f91709677b256e414 f1b53c8a2c8e4e30994a47decde9d3f0 c2ae9ce2f50f47d3886257ac8b91a14f--f1b53c8a2c8e4e30994a47decde9d3f0 6f99cd072e5f460f97f8f59fff6c3397 3 d0ccdbf02e58477ebfc60661f8a17a62 RX(theta₂) f1b53c8a2c8e4e30994a47decde9d3f0--d0ccdbf02e58477ebfc60661f8a17a62 a4f701c367a74208943954fad096226c RY(theta₆) d0ccdbf02e58477ebfc60661f8a17a62--a4f701c367a74208943954fad096226c 194c551782ef46a4856cc04bb7a2f44c RX(theta₁₀) a4f701c367a74208943954fad096226c--194c551782ef46a4856cc04bb7a2f44c f0e78c47dc3e4add8e9e206b54b524ff 194c551782ef46a4856cc04bb7a2f44c--f0e78c47dc3e4add8e9e206b54b524ff a366e04f47aa43ef9b1b3cd3a31c3ced X f0e78c47dc3e4add8e9e206b54b524ff--a366e04f47aa43ef9b1b3cd3a31c3ced a366e04f47aa43ef9b1b3cd3a31c3ced--e3d55fffe1ab4184868a0e54b5b502d9 0ae5b39cd42b4f3c984ce0973f78c193 RX(theta₁₄) a366e04f47aa43ef9b1b3cd3a31c3ced--0ae5b39cd42b4f3c984ce0973f78c193 96918e3b7ed44b2b8812157423c1e35a RY(theta₁₈) 0ae5b39cd42b4f3c984ce0973f78c193--96918e3b7ed44b2b8812157423c1e35a 2680b796edd6458aa1a182bf281695ff RX(theta₂₂) 96918e3b7ed44b2b8812157423c1e35a--2680b796edd6458aa1a182bf281695ff c2c60f096b534f24b77844209bf6377e 2680b796edd6458aa1a182bf281695ff--c2c60f096b534f24b77844209bf6377e 17be9f5cdbac4b57b46267b8d4e42e0e X c2c60f096b534f24b77844209bf6377e--17be9f5cdbac4b57b46267b8d4e42e0e 17be9f5cdbac4b57b46267b8d4e42e0e--f1c81b95af444298b8d0a88158696cb5 17be9f5cdbac4b57b46267b8d4e42e0e--786df64f6c20453f91709677b256e414 6a9ece07573a441e98eb9cc14a627aad e3e6494842e04ac5b6fb54962270d56e X 6f99cd072e5f460f97f8f59fff6c3397--e3e6494842e04ac5b6fb54962270d56e 06641eaa25c847308dcf0af1f52edc88 RX(theta₃) e3e6494842e04ac5b6fb54962270d56e--06641eaa25c847308dcf0af1f52edc88 9b3bae6861ce4861aea521f3a1bfe6b6 RY(theta₇) 06641eaa25c847308dcf0af1f52edc88--9b3bae6861ce4861aea521f3a1bfe6b6 9f990fb106744f20a069947dd3e8ee9d RX(theta₁₁) 9b3bae6861ce4861aea521f3a1bfe6b6--9f990fb106744f20a069947dd3e8ee9d faf3e6e957614f31aea8a4ac3eeb0049 X 9f990fb106744f20a069947dd3e8ee9d--faf3e6e957614f31aea8a4ac3eeb0049 faf3e6e957614f31aea8a4ac3eeb0049--f0e78c47dc3e4add8e9e206b54b524ff 7273d4fc64874cef9409c742ccd3f70c faf3e6e957614f31aea8a4ac3eeb0049--7273d4fc64874cef9409c742ccd3f70c 8dc81683fa1d4710a05a71152e3842cb RX(theta₁₅) 7273d4fc64874cef9409c742ccd3f70c--8dc81683fa1d4710a05a71152e3842cb 308cb3ce5ecf49729bd39ef8866e4ce5 RY(theta₁₉) 8dc81683fa1d4710a05a71152e3842cb--308cb3ce5ecf49729bd39ef8866e4ce5 1ed05a6ba2e34b808a840a345232f761 RX(theta₂₃) 308cb3ce5ecf49729bd39ef8866e4ce5--1ed05a6ba2e34b808a840a345232f761 0af88a8da04243d9b50459d36385fcc1 X 1ed05a6ba2e34b808a840a345232f761--0af88a8da04243d9b50459d36385fcc1 0af88a8da04243d9b50459d36385fcc1--c2c60f096b534f24b77844209bf6377e c4f28775f104493eafd4e253f91cc272 0af88a8da04243d9b50459d36385fcc1--c4f28775f104493eafd4e253f91cc272 c4f28775f104493eafd4e253f91cc272--6a9ece07573a441e98eb9cc14a627aad
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, 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, 1.+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.4733+0.0588j, -0.3286+0.0288j, -0.0680+0.3754j, -0.3299-0.1679j,
          0.0818+0.2296j, -0.2771-0.2593j, -0.0508+0.0349j,  0.1995-0.3662j],
        [-0.2293+0.0824j, -0.0980-0.0311j, -0.0049-0.1667j,  0.5866+0.3335j,
          0.1787+0.1656j,  0.0792-0.1512j, -0.5753+0.0789j,  0.1434-0.0244j]])

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