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.95905179+0.07257001j -0.27299549-0.02065716j  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_0615399263254fd0bf594511bb28d775 Circuit block cluster_b11e0bda350a476eb40f65dd0a7adf83 Prep block 1ae58760d0364f13928e5d318ee1f349 0 ea597de6f2b640e9a26589a52086339d 1ae58760d0364f13928e5d318ee1f349--ea597de6f2b640e9a26589a52086339d f186f7dbca3948cc8172b9dd0809c2b7 1 e28a6fdf47904623b21072d1cd991278 RX(theta₀) ea597de6f2b640e9a26589a52086339d--e28a6fdf47904623b21072d1cd991278 8b457b8b7c504dff81bb91ce49737911 RY(theta₄) e28a6fdf47904623b21072d1cd991278--8b457b8b7c504dff81bb91ce49737911 50f2807f7d844c879400d6706c788dd0 RX(theta₈) 8b457b8b7c504dff81bb91ce49737911--50f2807f7d844c879400d6706c788dd0 919b4f92024b4a9ba23aa3702cb1d679 50f2807f7d844c879400d6706c788dd0--919b4f92024b4a9ba23aa3702cb1d679 028fecffd9a048fe91c560c1d978adcb 919b4f92024b4a9ba23aa3702cb1d679--028fecffd9a048fe91c560c1d978adcb 0e5acd3b8722437c9a09601e348bbcb8 RX(theta₁₂) 028fecffd9a048fe91c560c1d978adcb--0e5acd3b8722437c9a09601e348bbcb8 b0c1f13644494922b12a494f9c1f6b2c RY(theta₁₆) 0e5acd3b8722437c9a09601e348bbcb8--b0c1f13644494922b12a494f9c1f6b2c d0ee0ca39a9a4fa0a0066ff8fbd9f5d7 RX(theta₂₀) b0c1f13644494922b12a494f9c1f6b2c--d0ee0ca39a9a4fa0a0066ff8fbd9f5d7 d8a764b718e2433ca2c48b506dc3ac4e d0ee0ca39a9a4fa0a0066ff8fbd9f5d7--d8a764b718e2433ca2c48b506dc3ac4e 0ef5f2b7338d4aeea2dbc3ceaf800446 d8a764b718e2433ca2c48b506dc3ac4e--0ef5f2b7338d4aeea2dbc3ceaf800446 9266657de044454d86f85907a1cbfdc5 0ef5f2b7338d4aeea2dbc3ceaf800446--9266657de044454d86f85907a1cbfdc5 ea818eba22e34c7d9ce505d91e701f93 68f4c7c5d06a4aba90f1297f0df31d57 f186f7dbca3948cc8172b9dd0809c2b7--68f4c7c5d06a4aba90f1297f0df31d57 e826cdd4a8d54b77a1140311c1a384c5 2 408aecedcecb44d1851ea5ebeac39aee RX(theta₁) 68f4c7c5d06a4aba90f1297f0df31d57--408aecedcecb44d1851ea5ebeac39aee 440baeed7e9349939745144836d1cf7a RY(theta₅) 408aecedcecb44d1851ea5ebeac39aee--440baeed7e9349939745144836d1cf7a e928bb401205488b912845e67dfe7cf5 RX(theta₉) 440baeed7e9349939745144836d1cf7a--e928bb401205488b912845e67dfe7cf5 0684a1d8cd424bfc903f6b8fa55fb05b X e928bb401205488b912845e67dfe7cf5--0684a1d8cd424bfc903f6b8fa55fb05b 0684a1d8cd424bfc903f6b8fa55fb05b--919b4f92024b4a9ba23aa3702cb1d679 921ccbf6a04c4064a7fa56c95f03943e 0684a1d8cd424bfc903f6b8fa55fb05b--921ccbf6a04c4064a7fa56c95f03943e be3f174334a545ecacada5535904e5c1 RX(theta₁₃) 921ccbf6a04c4064a7fa56c95f03943e--be3f174334a545ecacada5535904e5c1 47e8ca249ab9429fa43a9c91c71078a3 RY(theta₁₇) be3f174334a545ecacada5535904e5c1--47e8ca249ab9429fa43a9c91c71078a3 c8d8efe6e8834e80b5e50337b517f04f RX(theta₂₁) 47e8ca249ab9429fa43a9c91c71078a3--c8d8efe6e8834e80b5e50337b517f04f b2097f5ff8e6483b88b65aaa9217f354 X c8d8efe6e8834e80b5e50337b517f04f--b2097f5ff8e6483b88b65aaa9217f354 b2097f5ff8e6483b88b65aaa9217f354--d8a764b718e2433ca2c48b506dc3ac4e af825a338c0c437d8d12de7ecfb3fd80 b2097f5ff8e6483b88b65aaa9217f354--af825a338c0c437d8d12de7ecfb3fd80 af825a338c0c437d8d12de7ecfb3fd80--ea818eba22e34c7d9ce505d91e701f93 e02ddccdef9a4faba3eb8e211c2f6296 f090a31aaab24f37a7ac11fb2e928264 e826cdd4a8d54b77a1140311c1a384c5--f090a31aaab24f37a7ac11fb2e928264 0f99cc5ce99c4a6ab8f8795fd078c1e7 3 08ba275a5f554b46aa92778e96747b4f RX(theta₂) f090a31aaab24f37a7ac11fb2e928264--08ba275a5f554b46aa92778e96747b4f eb853549e72143dfac18f0b64f71f321 RY(theta₆) 08ba275a5f554b46aa92778e96747b4f--eb853549e72143dfac18f0b64f71f321 0134dec0cc41486b90eb489ace35bd1c RX(theta₁₀) eb853549e72143dfac18f0b64f71f321--0134dec0cc41486b90eb489ace35bd1c 364ae636655e420588ee2d4f94c72a30 0134dec0cc41486b90eb489ace35bd1c--364ae636655e420588ee2d4f94c72a30 550d9e969f994a8dba7cbe5a561bfc19 X 364ae636655e420588ee2d4f94c72a30--550d9e969f994a8dba7cbe5a561bfc19 550d9e969f994a8dba7cbe5a561bfc19--921ccbf6a04c4064a7fa56c95f03943e 4a2c5fce062d4504823ba64725255bb8 RX(theta₁₄) 550d9e969f994a8dba7cbe5a561bfc19--4a2c5fce062d4504823ba64725255bb8 6f21efd1cea1403eb44d7b5b5a5a2e21 RY(theta₁₈) 4a2c5fce062d4504823ba64725255bb8--6f21efd1cea1403eb44d7b5b5a5a2e21 2dd68537f40b4d9c9802666cf6b929c7 RX(theta₂₂) 6f21efd1cea1403eb44d7b5b5a5a2e21--2dd68537f40b4d9c9802666cf6b929c7 4e2a1cd8744946e196113f93aa7f006b 2dd68537f40b4d9c9802666cf6b929c7--4e2a1cd8744946e196113f93aa7f006b 1a73a48f68734774a1ca8e2cc17cd3d3 X 4e2a1cd8744946e196113f93aa7f006b--1a73a48f68734774a1ca8e2cc17cd3d3 1a73a48f68734774a1ca8e2cc17cd3d3--af825a338c0c437d8d12de7ecfb3fd80 1a73a48f68734774a1ca8e2cc17cd3d3--e02ddccdef9a4faba3eb8e211c2f6296 866e7fbc25b1492d88e5744f620797b2 bc93b688325b4ba6be8cd11439f619f7 X 0f99cc5ce99c4a6ab8f8795fd078c1e7--bc93b688325b4ba6be8cd11439f619f7 892c675e4b6a401ab275eed57414b482 RX(theta₃) bc93b688325b4ba6be8cd11439f619f7--892c675e4b6a401ab275eed57414b482 fb9f87320eac4e51b886d3881dec82eb RY(theta₇) 892c675e4b6a401ab275eed57414b482--fb9f87320eac4e51b886d3881dec82eb bdbd982335d44194b71847c63535c2be RX(theta₁₁) fb9f87320eac4e51b886d3881dec82eb--bdbd982335d44194b71847c63535c2be 3f348c15435d413995b3d7cb30d1b62b X bdbd982335d44194b71847c63535c2be--3f348c15435d413995b3d7cb30d1b62b 3f348c15435d413995b3d7cb30d1b62b--364ae636655e420588ee2d4f94c72a30 6ea47e76e93f4d4a9d12e8488b3dad02 3f348c15435d413995b3d7cb30d1b62b--6ea47e76e93f4d4a9d12e8488b3dad02 fe1c99727d75445d91bf777e5859e5b3 RX(theta₁₅) 6ea47e76e93f4d4a9d12e8488b3dad02--fe1c99727d75445d91bf777e5859e5b3 5d5d0a611f374f17974696098dbd7a23 RY(theta₁₉) fe1c99727d75445d91bf777e5859e5b3--5d5d0a611f374f17974696098dbd7a23 0192f760e7744a7184e3aaf5a053a922 RX(theta₂₃) 5d5d0a611f374f17974696098dbd7a23--0192f760e7744a7184e3aaf5a053a922 a820c08ae09e46c8b002858b46dc043f X 0192f760e7744a7184e3aaf5a053a922--a820c08ae09e46c8b002858b46dc043f a820c08ae09e46c8b002858b46dc043f--4e2a1cd8744946e196113f93aa7f006b 5b5d4add046e4f929af6b63e988c3c03 a820c08ae09e46c8b002858b46dc043f--5b5d4add046e4f929af6b63e988c3c03 5b5d4add046e4f929af6b63e988c3c03--866e7fbc25b1492d88e5744f620797b2
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, 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.4778-0.3032j, -0.2188+0.0063j, -0.5854+0.1054j, -0.0209+0.1171j,
         -0.1233+0.1146j,  0.2949-0.1529j,  0.2178+0.2514j,  0.0053+0.1206j],
        [ 0.0060+0.1147j,  0.1033+0.1432j, -0.2309+0.3088j, -0.2681+0.2402j,
         -0.2283-0.2065j, -0.4066+0.1532j, -0.5098-0.1379j,  0.2512-0.2275j]])

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