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.56230754+0.j -0.06783009+0.j  0.81821011+0.j -0.09869913+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)
cluster_e879252ef2c8498eaeddcec621b7ed57 Circuit block cluster_f27612b5626d473f8d8a34d3cb0d5589 Prep block 0f6ca2a940a647809008a9dc3fcdcfa1 0 fce42e0c13074984832123bf65f5f4eb 0f6ca2a940a647809008a9dc3fcdcfa1--fce42e0c13074984832123bf65f5f4eb 1724ebecbc7742629d08bd15bc93de46 1 5d980613b9094b8fba978a54adcbf425 RX(theta₀) fce42e0c13074984832123bf65f5f4eb--5d980613b9094b8fba978a54adcbf425 b35ad5f435ef439eb8135caa8edc10a3 RY(theta₄) 5d980613b9094b8fba978a54adcbf425--b35ad5f435ef439eb8135caa8edc10a3 38c08e53cb2c4cc3bc9ab883baf098dc RX(theta₈) b35ad5f435ef439eb8135caa8edc10a3--38c08e53cb2c4cc3bc9ab883baf098dc 19a2964ca754456eb625a0edf622a7c8 38c08e53cb2c4cc3bc9ab883baf098dc--19a2964ca754456eb625a0edf622a7c8 acd958717ffb44d89e31f4cce68f1cc1 19a2964ca754456eb625a0edf622a7c8--acd958717ffb44d89e31f4cce68f1cc1 b4052cff16b54e0b8a3332902203abb9 RX(theta₁₂) acd958717ffb44d89e31f4cce68f1cc1--b4052cff16b54e0b8a3332902203abb9 f4f9f4a8d68f474cb4fe0288a3b5be0c RY(theta₁₆) b4052cff16b54e0b8a3332902203abb9--f4f9f4a8d68f474cb4fe0288a3b5be0c f2827e67a5564b39ad83a567619e6c64 RX(theta₂₀) f4f9f4a8d68f474cb4fe0288a3b5be0c--f2827e67a5564b39ad83a567619e6c64 586ae13cce8947b0904f210c34c0e9a9 f2827e67a5564b39ad83a567619e6c64--586ae13cce8947b0904f210c34c0e9a9 c0990c02054c48c9b668b5c9f54f2076 586ae13cce8947b0904f210c34c0e9a9--c0990c02054c48c9b668b5c9f54f2076 069bc5d3ddc84b4fab6bddda90dcb114 c0990c02054c48c9b668b5c9f54f2076--069bc5d3ddc84b4fab6bddda90dcb114 465c7505c09a49c9891de8848fd77453 1d8f4009c38c443dab1a2a1ffa8fc34e 1724ebecbc7742629d08bd15bc93de46--1d8f4009c38c443dab1a2a1ffa8fc34e 45b4c5f2f60a4f3aa9c6b6cb76638357 2 2e26fa41513f47cd9ea9c189932baea8 RX(theta₁) 1d8f4009c38c443dab1a2a1ffa8fc34e--2e26fa41513f47cd9ea9c189932baea8 abe3353262c04bc38ba37e592864191d RY(theta₅) 2e26fa41513f47cd9ea9c189932baea8--abe3353262c04bc38ba37e592864191d 165c0c7416424bb69e5f7eb654f2e4d1 RX(theta₉) abe3353262c04bc38ba37e592864191d--165c0c7416424bb69e5f7eb654f2e4d1 8f90d4cd99d0439ab5566e089247844d X 165c0c7416424bb69e5f7eb654f2e4d1--8f90d4cd99d0439ab5566e089247844d 8f90d4cd99d0439ab5566e089247844d--19a2964ca754456eb625a0edf622a7c8 b26a031824b24ff5bf7595a8c58b656c 8f90d4cd99d0439ab5566e089247844d--b26a031824b24ff5bf7595a8c58b656c 7c149a1b4de94ae79d69515fd214fba3 RX(theta₁₃) b26a031824b24ff5bf7595a8c58b656c--7c149a1b4de94ae79d69515fd214fba3 2258549b1a684fd78d252ee6984ebb0f RY(theta₁₇) 7c149a1b4de94ae79d69515fd214fba3--2258549b1a684fd78d252ee6984ebb0f 0d0f2777bb5541f48a776cbf81be9c70 RX(theta₂₁) 2258549b1a684fd78d252ee6984ebb0f--0d0f2777bb5541f48a776cbf81be9c70 58a1dea87c2b45c6bbad71dc3bc0924e X 0d0f2777bb5541f48a776cbf81be9c70--58a1dea87c2b45c6bbad71dc3bc0924e 58a1dea87c2b45c6bbad71dc3bc0924e--586ae13cce8947b0904f210c34c0e9a9 30e84fef62104603b95b59f7db423e5f 58a1dea87c2b45c6bbad71dc3bc0924e--30e84fef62104603b95b59f7db423e5f 30e84fef62104603b95b59f7db423e5f--465c7505c09a49c9891de8848fd77453 42f2b62e7e704d0292d1f20114c8713b e302b9db5e7e4ea8a7135cedcd38e3d1 45b4c5f2f60a4f3aa9c6b6cb76638357--e302b9db5e7e4ea8a7135cedcd38e3d1 e3094f04a71c466dbdf22e9c41ea076f 3 5b8abb3091354e32be348d00fd44336b RX(theta₂) e302b9db5e7e4ea8a7135cedcd38e3d1--5b8abb3091354e32be348d00fd44336b d21e1f6ae13f41fd87d2a1162e574edb RY(theta₆) 5b8abb3091354e32be348d00fd44336b--d21e1f6ae13f41fd87d2a1162e574edb 769db2c48e83418b97d703fadfb3df68 RX(theta₁₀) d21e1f6ae13f41fd87d2a1162e574edb--769db2c48e83418b97d703fadfb3df68 84a1b9ca835943f785a039bfa71ae5ae 769db2c48e83418b97d703fadfb3df68--84a1b9ca835943f785a039bfa71ae5ae 895535506ba143be8b8b39bd1f7532d4 X 84a1b9ca835943f785a039bfa71ae5ae--895535506ba143be8b8b39bd1f7532d4 895535506ba143be8b8b39bd1f7532d4--b26a031824b24ff5bf7595a8c58b656c 3414e208d7b94bcba27734a294259bb2 RX(theta₁₄) 895535506ba143be8b8b39bd1f7532d4--3414e208d7b94bcba27734a294259bb2 33ebe6dc4093493cbfdd06dcaff65f82 RY(theta₁₈) 3414e208d7b94bcba27734a294259bb2--33ebe6dc4093493cbfdd06dcaff65f82 981a2e5fe2394d19b71e6c7342dcd712 RX(theta₂₂) 33ebe6dc4093493cbfdd06dcaff65f82--981a2e5fe2394d19b71e6c7342dcd712 8e49b9af9159401bbb8e7a251b6ced00 981a2e5fe2394d19b71e6c7342dcd712--8e49b9af9159401bbb8e7a251b6ced00 e4ab9425859b4207a115a30161b544b6 X 8e49b9af9159401bbb8e7a251b6ced00--e4ab9425859b4207a115a30161b544b6 e4ab9425859b4207a115a30161b544b6--30e84fef62104603b95b59f7db423e5f e4ab9425859b4207a115a30161b544b6--42f2b62e7e704d0292d1f20114c8713b 9edb0ee9b91645d29b55c0203b42a9d1 6e6be4729f8548fe986bfa9338d94597 X e3094f04a71c466dbdf22e9c41ea076f--6e6be4729f8548fe986bfa9338d94597 77afa7ae4b1b4f37b79eff779791275a RX(theta₃) 6e6be4729f8548fe986bfa9338d94597--77afa7ae4b1b4f37b79eff779791275a f11a6fe2ecae4692ab9a1c22665874a8 RY(theta₇) 77afa7ae4b1b4f37b79eff779791275a--f11a6fe2ecae4692ab9a1c22665874a8 f08f7a5c7570435288b165857e362051 RX(theta₁₁) f11a6fe2ecae4692ab9a1c22665874a8--f08f7a5c7570435288b165857e362051 171d38941b544b9a9a79de51de2d7ac0 X f08f7a5c7570435288b165857e362051--171d38941b544b9a9a79de51de2d7ac0 171d38941b544b9a9a79de51de2d7ac0--84a1b9ca835943f785a039bfa71ae5ae 5ef96144384b4323910b742910c2c629 171d38941b544b9a9a79de51de2d7ac0--5ef96144384b4323910b742910c2c629 b0d68868e17842309fcc9608d17e7631 RX(theta₁₅) 5ef96144384b4323910b742910c2c629--b0d68868e17842309fcc9608d17e7631 e717191dd8c241859aeb76d74f585114 RY(theta₁₉) b0d68868e17842309fcc9608d17e7631--e717191dd8c241859aeb76d74f585114 b11bb0fe6e6b4522ba29b96dd3e7c8d4 RX(theta₂₃) e717191dd8c241859aeb76d74f585114--b11bb0fe6e6b4522ba29b96dd3e7c8d4 e33670f5657c4e5db8a7a0571003962f X b11bb0fe6e6b4522ba29b96dd3e7c8d4--e33670f5657c4e5db8a7a0571003962f e33670f5657c4e5db8a7a0571003962f--8e49b9af9159401bbb8e7a251b6ced00 79ce0a8b4e6b4e659b37d6053e5539a0 e33670f5657c4e5db8a7a0571003962f--79ce0a8b4e6b4e659b37d6053e5539a0 79ce0a8b4e6b4e659b37d6053e5539a0--9edb0ee9b91645d29b55c0203b42a9d1
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)
├── 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]])