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.89529433+0.33257402j 0.10320625-0.27783278j 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_c6e3d92a428c4d56b6481f1926fc0dec Circuit block cluster_f37fe3e7a62d4269a2bafb39e3b67b72 Prep block 3ba56a1b3b294fcc89834314ad1068d7 0 eaa8c1006bd44622b3e2dcccbe2ebbb7 3ba56a1b3b294fcc89834314ad1068d7--eaa8c1006bd44622b3e2dcccbe2ebbb7 bbab1633be104ecba0db3b14c334999d 1 4ea81152a7e3479eb2b56f5b9ec87a35 RX(theta₀) eaa8c1006bd44622b3e2dcccbe2ebbb7--4ea81152a7e3479eb2b56f5b9ec87a35 e196f9d88c3f46a4ba80ed4878ed05bd RY(theta₄) 4ea81152a7e3479eb2b56f5b9ec87a35--e196f9d88c3f46a4ba80ed4878ed05bd 57390375b81b4d43a5788590be49edf2 RX(theta₈) e196f9d88c3f46a4ba80ed4878ed05bd--57390375b81b4d43a5788590be49edf2 8401ac79550b45e9bcc8ecb50fcd440b 57390375b81b4d43a5788590be49edf2--8401ac79550b45e9bcc8ecb50fcd440b c229a8c831b043c5b4ffd74e56c25bfb 8401ac79550b45e9bcc8ecb50fcd440b--c229a8c831b043c5b4ffd74e56c25bfb 4f103a809d004984a8c8ae271d21efe6 RX(theta₁₂) c229a8c831b043c5b4ffd74e56c25bfb--4f103a809d004984a8c8ae271d21efe6 3dea88a50caf48beacb6de940b95f6ea RY(theta₁₆) 4f103a809d004984a8c8ae271d21efe6--3dea88a50caf48beacb6de940b95f6ea 2e57c68de40246759a49401973ee39ae RX(theta₂₀) 3dea88a50caf48beacb6de940b95f6ea--2e57c68de40246759a49401973ee39ae 4ef6fdda9bec4305811e94eedcf1db82 2e57c68de40246759a49401973ee39ae--4ef6fdda9bec4305811e94eedcf1db82 5ac0a13558f64e9dad8358e4019cb5e9 4ef6fdda9bec4305811e94eedcf1db82--5ac0a13558f64e9dad8358e4019cb5e9 1bdf2c04e5704802be801facead05510 5ac0a13558f64e9dad8358e4019cb5e9--1bdf2c04e5704802be801facead05510 261b6373776c46a2884d481df5ef664a 0f2a64550608432b9e05d0da929941bd bbab1633be104ecba0db3b14c334999d--0f2a64550608432b9e05d0da929941bd a7fd7bfba5a643b7820d35bc345013cd 2 07fbe7fbbaf540638cb82f091cb16ebd RX(theta₁) 0f2a64550608432b9e05d0da929941bd--07fbe7fbbaf540638cb82f091cb16ebd 1ad9c0fa876340a59cfcd571e0560359 RY(theta₅) 07fbe7fbbaf540638cb82f091cb16ebd--1ad9c0fa876340a59cfcd571e0560359 fc0094f8709d4dbfb9b0f538449c6d22 RX(theta₉) 1ad9c0fa876340a59cfcd571e0560359--fc0094f8709d4dbfb9b0f538449c6d22 c221dccb773a4afaaabbe613c126305e X fc0094f8709d4dbfb9b0f538449c6d22--c221dccb773a4afaaabbe613c126305e c221dccb773a4afaaabbe613c126305e--8401ac79550b45e9bcc8ecb50fcd440b 3e2b7fe4d486438baa79b733d5d226a3 c221dccb773a4afaaabbe613c126305e--3e2b7fe4d486438baa79b733d5d226a3 85b073a8df784cffb0d35eb2e13a6cb1 RX(theta₁₃) 3e2b7fe4d486438baa79b733d5d226a3--85b073a8df784cffb0d35eb2e13a6cb1 35cd634b77c441828048768a72c8f3e6 RY(theta₁₇) 85b073a8df784cffb0d35eb2e13a6cb1--35cd634b77c441828048768a72c8f3e6 6e035472dfad4f84a5dda612c71fa5d0 RX(theta₂₁) 35cd634b77c441828048768a72c8f3e6--6e035472dfad4f84a5dda612c71fa5d0 8fe20ddd22eb40bdba4721a96195a0bc X 6e035472dfad4f84a5dda612c71fa5d0--8fe20ddd22eb40bdba4721a96195a0bc 8fe20ddd22eb40bdba4721a96195a0bc--4ef6fdda9bec4305811e94eedcf1db82 54ace213bed74eaf9fc26c45452a3cf0 8fe20ddd22eb40bdba4721a96195a0bc--54ace213bed74eaf9fc26c45452a3cf0 54ace213bed74eaf9fc26c45452a3cf0--261b6373776c46a2884d481df5ef664a cf76aa06b6c44dbaa6e12e0dfcfbf188 63d9cc8f71e94af08c19f4132f587955 a7fd7bfba5a643b7820d35bc345013cd--63d9cc8f71e94af08c19f4132f587955 5a408b691bcd4af1830850629a7edfba 3 2a36b9ca00d8439e893bd263e0b598e7 RX(theta₂) 63d9cc8f71e94af08c19f4132f587955--2a36b9ca00d8439e893bd263e0b598e7 183febb7cc434a4fbcfc8b4433a5d81b RY(theta₆) 2a36b9ca00d8439e893bd263e0b598e7--183febb7cc434a4fbcfc8b4433a5d81b b71e451c09504b3ea226b8792d50ba2c RX(theta₁₀) 183febb7cc434a4fbcfc8b4433a5d81b--b71e451c09504b3ea226b8792d50ba2c 18ff83dc2fad41cf886470277a32461a b71e451c09504b3ea226b8792d50ba2c--18ff83dc2fad41cf886470277a32461a bbb41dd3276248eda2d1059aebd02395 X 18ff83dc2fad41cf886470277a32461a--bbb41dd3276248eda2d1059aebd02395 bbb41dd3276248eda2d1059aebd02395--3e2b7fe4d486438baa79b733d5d226a3 1fa55d3af5b64d0eb96f3d181e325515 RX(theta₁₄) bbb41dd3276248eda2d1059aebd02395--1fa55d3af5b64d0eb96f3d181e325515 b3c08827b18848d5a959f8f00a91f1fc RY(theta₁₈) 1fa55d3af5b64d0eb96f3d181e325515--b3c08827b18848d5a959f8f00a91f1fc 9b876644176b4fe590012c200b8b4ff8 RX(theta₂₂) b3c08827b18848d5a959f8f00a91f1fc--9b876644176b4fe590012c200b8b4ff8 6a6e014fed964e0d85d5d16ca631309b 9b876644176b4fe590012c200b8b4ff8--6a6e014fed964e0d85d5d16ca631309b 73453fcf3d98488ba0cc4cfccd16c66a X 6a6e014fed964e0d85d5d16ca631309b--73453fcf3d98488ba0cc4cfccd16c66a 73453fcf3d98488ba0cc4cfccd16c66a--54ace213bed74eaf9fc26c45452a3cf0 73453fcf3d98488ba0cc4cfccd16c66a--cf76aa06b6c44dbaa6e12e0dfcfbf188 526c12ae59444b0aaafc2efa8e536a8a 5522c16a739242a7a6594ae9493c2a25 X 5a408b691bcd4af1830850629a7edfba--5522c16a739242a7a6594ae9493c2a25 f1ff059629ce4f8cb921af7c3f747fab RX(theta₃) 5522c16a739242a7a6594ae9493c2a25--f1ff059629ce4f8cb921af7c3f747fab be8074aa56174efc92adc934dc638625 RY(theta₇) f1ff059629ce4f8cb921af7c3f747fab--be8074aa56174efc92adc934dc638625 d237be3dde094f278414953667cfbbc6 RX(theta₁₁) be8074aa56174efc92adc934dc638625--d237be3dde094f278414953667cfbbc6 14ac4c22757e4b78b7204b471cdcffbe X d237be3dde094f278414953667cfbbc6--14ac4c22757e4b78b7204b471cdcffbe 14ac4c22757e4b78b7204b471cdcffbe--18ff83dc2fad41cf886470277a32461a bde2eb7e3cff47239e8835cb9e3d0bd8 14ac4c22757e4b78b7204b471cdcffbe--bde2eb7e3cff47239e8835cb9e3d0bd8 a759e6d806954247a3d28f81df203599 RX(theta₁₅) bde2eb7e3cff47239e8835cb9e3d0bd8--a759e6d806954247a3d28f81df203599 86337e3702c64a979c31762d695e0a8e RY(theta₁₉) a759e6d806954247a3d28f81df203599--86337e3702c64a979c31762d695e0a8e c17ecece75a24510a47e853f8ae0105e RX(theta₂₃) 86337e3702c64a979c31762d695e0a8e--c17ecece75a24510a47e853f8ae0105e 42e4874bd64c41c7a8c71bc084a72e71 X c17ecece75a24510a47e853f8ae0105e--42e4874bd64c41c7a8c71bc084a72e71 42e4874bd64c41c7a8c71bc084a72e71--6a6e014fed964e0d85d5d16ca631309b f5661f5ae8984ef99d5ceee8f367908d 42e4874bd64c41c7a8c71bc084a72e71--f5661f5ae8984ef99d5ceee8f367908d f5661f5ae8984ef99d5ceee8f367908d--526c12ae59444b0aaafc2efa8e536a8a
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]])