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.92042346+0.3752344j  0.        +0.j         0.04138827-0.10152249j
 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_4ce0ffa4c4014c75a5013de6b12d6d64 Circuit block cluster_9865317ca55e498fbab90c3d3bba2768 Prep block 5ac13b0f433c438d9d7e906678d2f934 0 8378db0bf9e149059b3e629b320d283a 5ac13b0f433c438d9d7e906678d2f934--8378db0bf9e149059b3e629b320d283a daac939040d645bea53fa94662c16877 1 200fc41532624bf886080c354b281b7d RX(theta₀) 8378db0bf9e149059b3e629b320d283a--200fc41532624bf886080c354b281b7d 5cb90460d2b841878cde2c5ee2dc6847 RY(theta₄) 200fc41532624bf886080c354b281b7d--5cb90460d2b841878cde2c5ee2dc6847 8f75cda9aefb4523b9094f23a646b9bd RX(theta₈) 5cb90460d2b841878cde2c5ee2dc6847--8f75cda9aefb4523b9094f23a646b9bd f833f0090c4546beb255b838762a25c4 8f75cda9aefb4523b9094f23a646b9bd--f833f0090c4546beb255b838762a25c4 dbb671eccb3e4c90bd13062023a089fd f833f0090c4546beb255b838762a25c4--dbb671eccb3e4c90bd13062023a089fd 179ab97d1a1d4fedad0a5243544fd53f RX(theta₁₂) dbb671eccb3e4c90bd13062023a089fd--179ab97d1a1d4fedad0a5243544fd53f bc0fd4642da34696ba4f9c00c2e67e87 RY(theta₁₆) 179ab97d1a1d4fedad0a5243544fd53f--bc0fd4642da34696ba4f9c00c2e67e87 148dbc86059846a48e6277d2d518f07e RX(theta₂₀) bc0fd4642da34696ba4f9c00c2e67e87--148dbc86059846a48e6277d2d518f07e 64404bceffc44f498f3212716a804a4c 148dbc86059846a48e6277d2d518f07e--64404bceffc44f498f3212716a804a4c b3d87d73d500410d8901bc35994c7998 64404bceffc44f498f3212716a804a4c--b3d87d73d500410d8901bc35994c7998 6933d65e8ca24d66bd9929fc549586ab b3d87d73d500410d8901bc35994c7998--6933d65e8ca24d66bd9929fc549586ab 3d35f86a1e5944228652b52fd9faf7ad 799e1baa7972495eb0e36e2d4e4aa534 daac939040d645bea53fa94662c16877--799e1baa7972495eb0e36e2d4e4aa534 6d87e87f642647c9b5b6e2a61874cdef 2 017bc6d239584849b03fb8a556520677 RX(theta₁) 799e1baa7972495eb0e36e2d4e4aa534--017bc6d239584849b03fb8a556520677 4e8e81b632ba4b8dac1bb213fe193a0e RY(theta₅) 017bc6d239584849b03fb8a556520677--4e8e81b632ba4b8dac1bb213fe193a0e 09518538f27b4709b5a28c6a7d926f5f RX(theta₉) 4e8e81b632ba4b8dac1bb213fe193a0e--09518538f27b4709b5a28c6a7d926f5f 462c0a63b286473e9fb7182f5241e6a2 X 09518538f27b4709b5a28c6a7d926f5f--462c0a63b286473e9fb7182f5241e6a2 462c0a63b286473e9fb7182f5241e6a2--f833f0090c4546beb255b838762a25c4 99d33b73a1f1418b918bfe2fb618ecca 462c0a63b286473e9fb7182f5241e6a2--99d33b73a1f1418b918bfe2fb618ecca f06f4e6da5814a11b40a616485ff6c0b RX(theta₁₃) 99d33b73a1f1418b918bfe2fb618ecca--f06f4e6da5814a11b40a616485ff6c0b 755c7f842aaf472f9dee99f5962edc89 RY(theta₁₇) f06f4e6da5814a11b40a616485ff6c0b--755c7f842aaf472f9dee99f5962edc89 0a07b56b7456456d80bbd47717209fd8 RX(theta₂₁) 755c7f842aaf472f9dee99f5962edc89--0a07b56b7456456d80bbd47717209fd8 61bf95e14f2148829075aeb839fe4b42 X 0a07b56b7456456d80bbd47717209fd8--61bf95e14f2148829075aeb839fe4b42 61bf95e14f2148829075aeb839fe4b42--64404bceffc44f498f3212716a804a4c 9b0fb3cee35242c4a8d3d05378919920 61bf95e14f2148829075aeb839fe4b42--9b0fb3cee35242c4a8d3d05378919920 9b0fb3cee35242c4a8d3d05378919920--3d35f86a1e5944228652b52fd9faf7ad a2aa1cb112474c99b546205cb3c34d8c b9d9fc3d19e840d992ef8d2ffcfdc136 6d87e87f642647c9b5b6e2a61874cdef--b9d9fc3d19e840d992ef8d2ffcfdc136 18095005a0414805b00457707842deaa 3 93cbba6bef3348d38b3c5efb63de1b81 RX(theta₂) b9d9fc3d19e840d992ef8d2ffcfdc136--93cbba6bef3348d38b3c5efb63de1b81 f3f182fd6fca44fea4d1296184730a25 RY(theta₆) 93cbba6bef3348d38b3c5efb63de1b81--f3f182fd6fca44fea4d1296184730a25 03af64b6419746a6a9634f0301b20c85 RX(theta₁₀) f3f182fd6fca44fea4d1296184730a25--03af64b6419746a6a9634f0301b20c85 893463695d174a03accdaeed50f01280 03af64b6419746a6a9634f0301b20c85--893463695d174a03accdaeed50f01280 0cd41e1877f646cda0af5673a4d49706 X 893463695d174a03accdaeed50f01280--0cd41e1877f646cda0af5673a4d49706 0cd41e1877f646cda0af5673a4d49706--99d33b73a1f1418b918bfe2fb618ecca 9549f6b7c6594a12917d5d327f8ac5fe RX(theta₁₄) 0cd41e1877f646cda0af5673a4d49706--9549f6b7c6594a12917d5d327f8ac5fe af8c951fbf07496d8dad754d183522b2 RY(theta₁₈) 9549f6b7c6594a12917d5d327f8ac5fe--af8c951fbf07496d8dad754d183522b2 5f4f1b281425456cb64d38adac536ece RX(theta₂₂) af8c951fbf07496d8dad754d183522b2--5f4f1b281425456cb64d38adac536ece 47334c3310a54b39ab437161fac26ce7 5f4f1b281425456cb64d38adac536ece--47334c3310a54b39ab437161fac26ce7 b42cb6c38da4499db2669e47de1453e4 X 47334c3310a54b39ab437161fac26ce7--b42cb6c38da4499db2669e47de1453e4 b42cb6c38da4499db2669e47de1453e4--9b0fb3cee35242c4a8d3d05378919920 b42cb6c38da4499db2669e47de1453e4--a2aa1cb112474c99b546205cb3c34d8c 2ae737e7a4d1470cb8ce4db8feaaaf42 01cb8012612248e887f2794104e43335 X 18095005a0414805b00457707842deaa--01cb8012612248e887f2794104e43335 13179a6ddc9547bca093b68633037a83 RX(theta₃) 01cb8012612248e887f2794104e43335--13179a6ddc9547bca093b68633037a83 2c61c73f51dc49a7a659152f667b8001 RY(theta₇) 13179a6ddc9547bca093b68633037a83--2c61c73f51dc49a7a659152f667b8001 26e10f7305234eb98f37ef93758298b1 RX(theta₁₁) 2c61c73f51dc49a7a659152f667b8001--26e10f7305234eb98f37ef93758298b1 7bf478e2aaa548d7b8d4c94a263d1de1 X 26e10f7305234eb98f37ef93758298b1--7bf478e2aaa548d7b8d4c94a263d1de1 7bf478e2aaa548d7b8d4c94a263d1de1--893463695d174a03accdaeed50f01280 bf1639986d8043ac9e2a5475a433728d 7bf478e2aaa548d7b8d4c94a263d1de1--bf1639986d8043ac9e2a5475a433728d 8cb727d5542d4538825ac5026c8c1895 RX(theta₁₅) bf1639986d8043ac9e2a5475a433728d--8cb727d5542d4538825ac5026c8c1895 9078fd91f82a4e98824450c4a57b80da RY(theta₁₉) 8cb727d5542d4538825ac5026c8c1895--9078fd91f82a4e98824450c4a57b80da 7ed693e5e6e94fc2a3561b7057e3e1b1 RX(theta₂₃) 9078fd91f82a4e98824450c4a57b80da--7ed693e5e6e94fc2a3561b7057e3e1b1 3bfbd2017efb452f8fbe902ffa0400db X 7ed693e5e6e94fc2a3561b7057e3e1b1--3bfbd2017efb452f8fbe902ffa0400db 3bfbd2017efb452f8fbe902ffa0400db--47334c3310a54b39ab437161fac26ce7 de7f455ca6c14d56b3465633c2924551 3bfbd2017efb452f8fbe902ffa0400db--de7f455ca6c14d56b3465633c2924551 de7f455ca6c14d56b3465633c2924551--2ae737e7a4d1470cb8ce4db8feaaaf42
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, 0.+0.j, 1.+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.1938-0.0520j, -0.2004+0.3661j, -0.0483-0.0577j, -0.2657-0.3253j,
          0.4508+0.0664j,  0.2878+0.0577j, -0.2979+0.1222j, -0.0662+0.4491j],
        [ 0.2315-0.2451j,  0.2807+0.1053j, -0.3644+0.4587j, -0.0791+0.0530j,
         -0.0125-0.1685j,  0.2731-0.3878j, -0.3455-0.2506j, -0.0893-0.0241j]])

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