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.95253032+0.j         -0.10844744+0.j          0.        +0.28264746j
  0.        -0.03217997j]

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_adec49aeab104c7a841905e8af0158a1 Circuit block cluster_af23ca15e328457daf5bde77461716c7 Prep block 457ccabd80d241e98ea4645f77e4bdb9 0 fca63722c1974f68a99547d6ab15a01b 457ccabd80d241e98ea4645f77e4bdb9--fca63722c1974f68a99547d6ab15a01b de612bba5e974d4190caebcaa3c3488e 1 76b7f839d89c41ada2285dd0a8b6a47c RX(theta₀) fca63722c1974f68a99547d6ab15a01b--76b7f839d89c41ada2285dd0a8b6a47c 2da92035c29c49c494a86682a361b400 RY(theta₄) 76b7f839d89c41ada2285dd0a8b6a47c--2da92035c29c49c494a86682a361b400 edd0d72726474d08b1b5a6ad7a0bcd71 RX(theta₈) 2da92035c29c49c494a86682a361b400--edd0d72726474d08b1b5a6ad7a0bcd71 d7192745e9c54ae799727974dff9af84 edd0d72726474d08b1b5a6ad7a0bcd71--d7192745e9c54ae799727974dff9af84 b026004a381b4c02b79261ed50cbb22a d7192745e9c54ae799727974dff9af84--b026004a381b4c02b79261ed50cbb22a 305e080dbaa645e782c57b58d132b5f2 RX(theta₁₂) b026004a381b4c02b79261ed50cbb22a--305e080dbaa645e782c57b58d132b5f2 06ad38f252824f0993e0e4ee90a99b2f RY(theta₁₆) 305e080dbaa645e782c57b58d132b5f2--06ad38f252824f0993e0e4ee90a99b2f 0ce99803a92f4021887d91d41a635362 RX(theta₂₀) 06ad38f252824f0993e0e4ee90a99b2f--0ce99803a92f4021887d91d41a635362 272ca61d55ea494ba7bc96b85683fef8 0ce99803a92f4021887d91d41a635362--272ca61d55ea494ba7bc96b85683fef8 3083b5be70cc423da990bfc5211d0c08 272ca61d55ea494ba7bc96b85683fef8--3083b5be70cc423da990bfc5211d0c08 a50e7c62817046a2a3e9911b4dd72bbc 3083b5be70cc423da990bfc5211d0c08--a50e7c62817046a2a3e9911b4dd72bbc de1db80f467a47ce8b376b3165586bd9 5f80e8f4587a4865b664bc9ba29d674f de612bba5e974d4190caebcaa3c3488e--5f80e8f4587a4865b664bc9ba29d674f 6ca4018f163247f2930f928f58ff746d 2 648015422d074713b0cbaee95b81c220 RX(theta₁) 5f80e8f4587a4865b664bc9ba29d674f--648015422d074713b0cbaee95b81c220 9eb706f8457c4527b3992e8f7f548157 RY(theta₅) 648015422d074713b0cbaee95b81c220--9eb706f8457c4527b3992e8f7f548157 3965ab8459724fa88591877fe17ea016 RX(theta₉) 9eb706f8457c4527b3992e8f7f548157--3965ab8459724fa88591877fe17ea016 66c04216d397472398a0a5d5a7aef126 X 3965ab8459724fa88591877fe17ea016--66c04216d397472398a0a5d5a7aef126 66c04216d397472398a0a5d5a7aef126--d7192745e9c54ae799727974dff9af84 77a10a95016248239a7962dc1f819f4c 66c04216d397472398a0a5d5a7aef126--77a10a95016248239a7962dc1f819f4c a181fd14594643d8af97336e9a0310a2 RX(theta₁₃) 77a10a95016248239a7962dc1f819f4c--a181fd14594643d8af97336e9a0310a2 f83766efe776420fa1983b68fd0de1c1 RY(theta₁₇) a181fd14594643d8af97336e9a0310a2--f83766efe776420fa1983b68fd0de1c1 ffaa337a336142639f65b5d6c7cae445 RX(theta₂₁) f83766efe776420fa1983b68fd0de1c1--ffaa337a336142639f65b5d6c7cae445 6afd140fc2964f41806a8a9983dd8c85 X ffaa337a336142639f65b5d6c7cae445--6afd140fc2964f41806a8a9983dd8c85 6afd140fc2964f41806a8a9983dd8c85--272ca61d55ea494ba7bc96b85683fef8 bac0c20fd8ce4f7284186850711cba15 6afd140fc2964f41806a8a9983dd8c85--bac0c20fd8ce4f7284186850711cba15 bac0c20fd8ce4f7284186850711cba15--de1db80f467a47ce8b376b3165586bd9 c42d89d016f64592afef2476a4ee6c58 9cfeb83d926f445fa72d962c8e919169 6ca4018f163247f2930f928f58ff746d--9cfeb83d926f445fa72d962c8e919169 3d90d36aa9a14fb68046eaafccb1bb39 3 5637e08cb32d49d18047f35f03acae31 RX(theta₂) 9cfeb83d926f445fa72d962c8e919169--5637e08cb32d49d18047f35f03acae31 2b883fed0fdc46e98e1535d962f6a9c9 RY(theta₆) 5637e08cb32d49d18047f35f03acae31--2b883fed0fdc46e98e1535d962f6a9c9 27c8795073fa4c48963a321eda629fdc RX(theta₁₀) 2b883fed0fdc46e98e1535d962f6a9c9--27c8795073fa4c48963a321eda629fdc 17f9773736134546aec6f8fcccc4f26a 27c8795073fa4c48963a321eda629fdc--17f9773736134546aec6f8fcccc4f26a 8c7aa7127cdf42e393240b3f27755cf8 X 17f9773736134546aec6f8fcccc4f26a--8c7aa7127cdf42e393240b3f27755cf8 8c7aa7127cdf42e393240b3f27755cf8--77a10a95016248239a7962dc1f819f4c 9b3a306b8c9048b7aa7a64a39cb7bce0 RX(theta₁₄) 8c7aa7127cdf42e393240b3f27755cf8--9b3a306b8c9048b7aa7a64a39cb7bce0 7ebb7c3664b940b2bf204d63e29e57b7 RY(theta₁₈) 9b3a306b8c9048b7aa7a64a39cb7bce0--7ebb7c3664b940b2bf204d63e29e57b7 5894384466bb45308024a7ee17870c89 RX(theta₂₂) 7ebb7c3664b940b2bf204d63e29e57b7--5894384466bb45308024a7ee17870c89 c9d7a944221247b99ebbae833ada235a 5894384466bb45308024a7ee17870c89--c9d7a944221247b99ebbae833ada235a 1da1d1ebd3e74bbdbdb1ac1a47294634 X c9d7a944221247b99ebbae833ada235a--1da1d1ebd3e74bbdbdb1ac1a47294634 1da1d1ebd3e74bbdbdb1ac1a47294634--bac0c20fd8ce4f7284186850711cba15 1da1d1ebd3e74bbdbdb1ac1a47294634--c42d89d016f64592afef2476a4ee6c58 20212aad7b5a404f9f2b309246771318 44321e77f0b340debe1aabf677e61b16 X 3d90d36aa9a14fb68046eaafccb1bb39--44321e77f0b340debe1aabf677e61b16 9be0fcbf1eaa4ad29055128438bb52b0 RX(theta₃) 44321e77f0b340debe1aabf677e61b16--9be0fcbf1eaa4ad29055128438bb52b0 aa4da93917f143d5a7cc6a57d20ce2ce RY(theta₇) 9be0fcbf1eaa4ad29055128438bb52b0--aa4da93917f143d5a7cc6a57d20ce2ce 0ff87f2dcba64c0793df07f9b8be4c14 RX(theta₁₁) aa4da93917f143d5a7cc6a57d20ce2ce--0ff87f2dcba64c0793df07f9b8be4c14 7b886d1a1a2a4df8aabb99ce32fb07e9 X 0ff87f2dcba64c0793df07f9b8be4c14--7b886d1a1a2a4df8aabb99ce32fb07e9 7b886d1a1a2a4df8aabb99ce32fb07e9--17f9773736134546aec6f8fcccc4f26a f11e0e2102354accaa480f3b25eed5dd 7b886d1a1a2a4df8aabb99ce32fb07e9--f11e0e2102354accaa480f3b25eed5dd 773b8341c310478492dc0693b54ba89e RX(theta₁₅) f11e0e2102354accaa480f3b25eed5dd--773b8341c310478492dc0693b54ba89e 84b5f743c490441798f24d527a23e1ae RY(theta₁₉) 773b8341c310478492dc0693b54ba89e--84b5f743c490441798f24d527a23e1ae f928a936b76a458a871ff3dbcbaac049 RX(theta₂₃) 84b5f743c490441798f24d527a23e1ae--f928a936b76a458a871ff3dbcbaac049 16e3dbc12540451487c4ce4dba7a8bf3 X f928a936b76a458a871ff3dbcbaac049--16e3dbc12540451487c4ce4dba7a8bf3 16e3dbc12540451487c4ce4dba7a8bf3--c9d7a944221247b99ebbae833ada235a 7cc7560517ab414e871875c1bacb3227 16e3dbc12540451487c4ce4dba7a8bf3--7cc7560517ab414e871875c1bacb3227 7cc7560517ab414e871875c1bacb3227--20212aad7b5a404f9f2b309246771318
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, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+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.1413-0.0314j,  0.4271+0.0558j,  0.1211-0.0650j, -0.2887-0.3458j,
          0.1520-0.5908j, -0.2196-0.1824j,  0.0992-0.2272j,  0.2243+0.0795j],
        [ 0.3506+0.1673j,  0.0850-0.2147j, -0.0631+0.6737j,  0.0306+0.2123j,
          0.3492+0.2833j,  0.0531-0.1610j,  0.1590-0.0134j,  0.1670+0.0875j]])

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