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.4016671 +0.43579074j -0.54587946-0.59225467j  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_44e977e45fc6438095b664519e147114 Circuit block cluster_b90705f052af4126b68ca8df20d51860 Prep block 2bed3659cd7e425db6a74b059382b854 0 a80d21161cf44d7ba73467f91060fcc4 2bed3659cd7e425db6a74b059382b854--a80d21161cf44d7ba73467f91060fcc4 d5b75880cd8e4efabb515259652027de 1 76773ee0118645b6885a0fc08f10ecbb RX(theta₀) a80d21161cf44d7ba73467f91060fcc4--76773ee0118645b6885a0fc08f10ecbb 0cad3aadaf174d669222ada694b3bd26 RY(theta₄) 76773ee0118645b6885a0fc08f10ecbb--0cad3aadaf174d669222ada694b3bd26 172f4da7b77345d982edc99fc11b8669 RX(theta₈) 0cad3aadaf174d669222ada694b3bd26--172f4da7b77345d982edc99fc11b8669 eb924200a201486ca97655cc3cc63f0e 172f4da7b77345d982edc99fc11b8669--eb924200a201486ca97655cc3cc63f0e 42058d2c3ce546abaca9b88040fb631f eb924200a201486ca97655cc3cc63f0e--42058d2c3ce546abaca9b88040fb631f a51ef4c0d39847babc2d10c53c02acc2 RX(theta₁₂) 42058d2c3ce546abaca9b88040fb631f--a51ef4c0d39847babc2d10c53c02acc2 1c997fc185dc494b96703a1ed95f2a44 RY(theta₁₆) a51ef4c0d39847babc2d10c53c02acc2--1c997fc185dc494b96703a1ed95f2a44 03d9038149d74818bf72d8c6cc2b9db5 RX(theta₂₀) 1c997fc185dc494b96703a1ed95f2a44--03d9038149d74818bf72d8c6cc2b9db5 2c7cd52b309040e6acfee6c6519fdd7e 03d9038149d74818bf72d8c6cc2b9db5--2c7cd52b309040e6acfee6c6519fdd7e e62fc202152243929c1afae6ea0f7697 2c7cd52b309040e6acfee6c6519fdd7e--e62fc202152243929c1afae6ea0f7697 eb850f24d15d47809948360eb3ac1d94 e62fc202152243929c1afae6ea0f7697--eb850f24d15d47809948360eb3ac1d94 19d3fdb99d8047dcb479402cb9b7d096 e7b4444cb13c4f21b6737057a80932c3 d5b75880cd8e4efabb515259652027de--e7b4444cb13c4f21b6737057a80932c3 b4245318fad74e46b5e6af9040cc2a16 2 e4585e24d00844fb8f4e26ccde2c9052 RX(theta₁) e7b4444cb13c4f21b6737057a80932c3--e4585e24d00844fb8f4e26ccde2c9052 e92ff0a135244aa59d85bbf99d67e929 RY(theta₅) e4585e24d00844fb8f4e26ccde2c9052--e92ff0a135244aa59d85bbf99d67e929 c023274ccbb14907895c4a66de606e20 RX(theta₉) e92ff0a135244aa59d85bbf99d67e929--c023274ccbb14907895c4a66de606e20 9a3a64faca544afa9bc9719dd666ba0d X c023274ccbb14907895c4a66de606e20--9a3a64faca544afa9bc9719dd666ba0d 9a3a64faca544afa9bc9719dd666ba0d--eb924200a201486ca97655cc3cc63f0e f485ade02cbf453c818cd39d48c986fb 9a3a64faca544afa9bc9719dd666ba0d--f485ade02cbf453c818cd39d48c986fb b377bd5a92a5475582410b66e930c0d3 RX(theta₁₃) f485ade02cbf453c818cd39d48c986fb--b377bd5a92a5475582410b66e930c0d3 9500763df2264eb18848389c2c79f3e2 RY(theta₁₇) b377bd5a92a5475582410b66e930c0d3--9500763df2264eb18848389c2c79f3e2 0681d571252140dc9f2a75609d581dd5 RX(theta₂₁) 9500763df2264eb18848389c2c79f3e2--0681d571252140dc9f2a75609d581dd5 6c9b0d12521b4133922338a8bb08bb92 X 0681d571252140dc9f2a75609d581dd5--6c9b0d12521b4133922338a8bb08bb92 6c9b0d12521b4133922338a8bb08bb92--2c7cd52b309040e6acfee6c6519fdd7e 7ed3279db9254daca4b0bb7075c39acd 6c9b0d12521b4133922338a8bb08bb92--7ed3279db9254daca4b0bb7075c39acd 7ed3279db9254daca4b0bb7075c39acd--19d3fdb99d8047dcb479402cb9b7d096 ea1354ad2c1447589fb9df7d7997835b b579b547e0a3493890c3f43d25282728 b4245318fad74e46b5e6af9040cc2a16--b579b547e0a3493890c3f43d25282728 ef3629e643d94ebe99b306900bcaa9fd 3 f070d969fecb4c30853297536d3ddca3 RX(theta₂) b579b547e0a3493890c3f43d25282728--f070d969fecb4c30853297536d3ddca3 3a15c3c0b34c45d1b0b9086d5dc91dfc RY(theta₆) f070d969fecb4c30853297536d3ddca3--3a15c3c0b34c45d1b0b9086d5dc91dfc 5c464b20fe4c4bdc8a341790bdac0568 RX(theta₁₀) 3a15c3c0b34c45d1b0b9086d5dc91dfc--5c464b20fe4c4bdc8a341790bdac0568 2ef39b6d00e74b449e177e55636b45f8 5c464b20fe4c4bdc8a341790bdac0568--2ef39b6d00e74b449e177e55636b45f8 4c5dff52e05f4f97b0762ab5e654f3e4 X 2ef39b6d00e74b449e177e55636b45f8--4c5dff52e05f4f97b0762ab5e654f3e4 4c5dff52e05f4f97b0762ab5e654f3e4--f485ade02cbf453c818cd39d48c986fb 3603eda4834640e88a9c359814b0da62 RX(theta₁₄) 4c5dff52e05f4f97b0762ab5e654f3e4--3603eda4834640e88a9c359814b0da62 6aef37e2594b490bbb714b949391c9f4 RY(theta₁₈) 3603eda4834640e88a9c359814b0da62--6aef37e2594b490bbb714b949391c9f4 ed789c6a682143278f02021b40ac9729 RX(theta₂₂) 6aef37e2594b490bbb714b949391c9f4--ed789c6a682143278f02021b40ac9729 e2153ac5471549d5bd0d1fd9877adbb0 ed789c6a682143278f02021b40ac9729--e2153ac5471549d5bd0d1fd9877adbb0 839e65e61b3f461698d50d9171e139ab X e2153ac5471549d5bd0d1fd9877adbb0--839e65e61b3f461698d50d9171e139ab 839e65e61b3f461698d50d9171e139ab--7ed3279db9254daca4b0bb7075c39acd 839e65e61b3f461698d50d9171e139ab--ea1354ad2c1447589fb9df7d7997835b e881ccdc3d444a1681f80d26b8f3e8ea 443d0b1c841b434a9a546fafaf701a0e X ef3629e643d94ebe99b306900bcaa9fd--443d0b1c841b434a9a546fafaf701a0e 589c3530fca64a8185e0335008f8feb4 RX(theta₃) 443d0b1c841b434a9a546fafaf701a0e--589c3530fca64a8185e0335008f8feb4 94e260f846ef4ff9b83353c24b0dbb56 RY(theta₇) 589c3530fca64a8185e0335008f8feb4--94e260f846ef4ff9b83353c24b0dbb56 22692a1ffca34bb89108dc48d137dcb2 RX(theta₁₁) 94e260f846ef4ff9b83353c24b0dbb56--22692a1ffca34bb89108dc48d137dcb2 168fede553da44db9618493ccb84345b X 22692a1ffca34bb89108dc48d137dcb2--168fede553da44db9618493ccb84345b 168fede553da44db9618493ccb84345b--2ef39b6d00e74b449e177e55636b45f8 6a26887d8ccf48788d6edb1c3d7483ea 168fede553da44db9618493ccb84345b--6a26887d8ccf48788d6edb1c3d7483ea d0ff9ee9a5a34b219951572454734176 RX(theta₁₅) 6a26887d8ccf48788d6edb1c3d7483ea--d0ff9ee9a5a34b219951572454734176 f6a946e93751467a834847b08f546c70 RY(theta₁₉) d0ff9ee9a5a34b219951572454734176--f6a946e93751467a834847b08f546c70 2e1495cd30f64d879564eff62e14c851 RX(theta₂₃) f6a946e93751467a834847b08f546c70--2e1495cd30f64d879564eff62e14c851 7af6e13ba93440ba925f9e64604424b4 X 2e1495cd30f64d879564eff62e14c851--7af6e13ba93440ba925f9e64604424b4 7af6e13ba93440ba925f9e64604424b4--e2153ac5471549d5bd0d1fd9877adbb0 dae9c6d453d64c8191f80d698e87f77e 7af6e13ba93440ba925f9e64604424b4--dae9c6d453d64c8191f80d698e87f77e dae9c6d453d64c8191f80d698e87f77e--e881ccdc3d444a1681f80d26b8f3e8ea
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, 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, 1.+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.2390-0.1881j,  0.1646-0.0699j, -0.4417-0.1439j, -0.1631+0.1908j,
          0.0305-0.2692j,  0.2547+0.0842j,  0.1633+0.2059j, -0.2162-0.5792j],
        [ 0.0061+0.1679j,  0.1055+0.2131j, -0.1951-0.0451j,  0.0293+0.2837j,
         -0.1773+0.3076j, -0.0885+0.0918j,  0.4380+0.4700j, -0.3802+0.3070j]])

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