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.46333446+0.31591776j  0.        +0.j         -0.68407745-0.46642811j
  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_106a0701258244b48ca7c84ae8d1ac27 Circuit block cluster_6625fe09b869473eae9bc0ec64ba38df Prep block e9337dc72e9a4e9693643f0ca7c30fa1 0 f7f48c86ca02410abab2b005998bf74a e9337dc72e9a4e9693643f0ca7c30fa1--f7f48c86ca02410abab2b005998bf74a 0e8d1aacdab148999772dde9804bcd1b 1 ea8b91f231a949e0b274df0bbfe374f6 RX(theta₀) f7f48c86ca02410abab2b005998bf74a--ea8b91f231a949e0b274df0bbfe374f6 f9f5fd2740834abea6858995f95537b9 RY(theta₄) ea8b91f231a949e0b274df0bbfe374f6--f9f5fd2740834abea6858995f95537b9 f2d1daebea3249909dfd8b4778458355 RX(theta₈) f9f5fd2740834abea6858995f95537b9--f2d1daebea3249909dfd8b4778458355 692875b345184fefafcdbbdff0b79baf f2d1daebea3249909dfd8b4778458355--692875b345184fefafcdbbdff0b79baf c91ff8e79b1447589685fa8d1e2ec527 692875b345184fefafcdbbdff0b79baf--c91ff8e79b1447589685fa8d1e2ec527 c8c650f2ff044889a3817645fe7b1db3 RX(theta₁₂) c91ff8e79b1447589685fa8d1e2ec527--c8c650f2ff044889a3817645fe7b1db3 f5cfb6dc89944bc8be33edad18eb262d RY(theta₁₆) c8c650f2ff044889a3817645fe7b1db3--f5cfb6dc89944bc8be33edad18eb262d 4c757e3e3f0a4e23b786c737100adb50 RX(theta₂₀) f5cfb6dc89944bc8be33edad18eb262d--4c757e3e3f0a4e23b786c737100adb50 7b0dab3b65a34b62bcc14210ce435d88 4c757e3e3f0a4e23b786c737100adb50--7b0dab3b65a34b62bcc14210ce435d88 b6d8511cc8894226a8b4cd7a263a9cbc 7b0dab3b65a34b62bcc14210ce435d88--b6d8511cc8894226a8b4cd7a263a9cbc 15e7dd7b09cf47c4a0fc9648422d8de6 b6d8511cc8894226a8b4cd7a263a9cbc--15e7dd7b09cf47c4a0fc9648422d8de6 30c5731c85f44f3cb6022536f5316e43 2abf8579e2c94a0fb374ba7c20210f7f 0e8d1aacdab148999772dde9804bcd1b--2abf8579e2c94a0fb374ba7c20210f7f 3159117f7e954df9b9726ec0331cfe89 2 f6416644d85d43a5a3dedd45c8ba4ae1 RX(theta₁) 2abf8579e2c94a0fb374ba7c20210f7f--f6416644d85d43a5a3dedd45c8ba4ae1 c28a6048fb25466f997871df8e85c882 RY(theta₅) f6416644d85d43a5a3dedd45c8ba4ae1--c28a6048fb25466f997871df8e85c882 a7aab4dfe0f2460f85708bd18d4626b9 RX(theta₉) c28a6048fb25466f997871df8e85c882--a7aab4dfe0f2460f85708bd18d4626b9 07a2884dff2d4dd99403e1c7e07650ae X a7aab4dfe0f2460f85708bd18d4626b9--07a2884dff2d4dd99403e1c7e07650ae 07a2884dff2d4dd99403e1c7e07650ae--692875b345184fefafcdbbdff0b79baf e6d84a2e31a44324bf47f0b6d3f783a9 07a2884dff2d4dd99403e1c7e07650ae--e6d84a2e31a44324bf47f0b6d3f783a9 aced877cacfc45ff95d4c8f754db4b8c RX(theta₁₃) e6d84a2e31a44324bf47f0b6d3f783a9--aced877cacfc45ff95d4c8f754db4b8c b8ac1300ae0f41dd979d993ab0cf04f1 RY(theta₁₇) aced877cacfc45ff95d4c8f754db4b8c--b8ac1300ae0f41dd979d993ab0cf04f1 8748b993a6c34262b0c7e3d1c418b08d RX(theta₂₁) b8ac1300ae0f41dd979d993ab0cf04f1--8748b993a6c34262b0c7e3d1c418b08d 3023dcf86d014106b3890ef8edc9c79a X 8748b993a6c34262b0c7e3d1c418b08d--3023dcf86d014106b3890ef8edc9c79a 3023dcf86d014106b3890ef8edc9c79a--7b0dab3b65a34b62bcc14210ce435d88 3daa71f3231b454cbb8a29f0761a9f91 3023dcf86d014106b3890ef8edc9c79a--3daa71f3231b454cbb8a29f0761a9f91 3daa71f3231b454cbb8a29f0761a9f91--30c5731c85f44f3cb6022536f5316e43 36e2f7b5444b45a18e1b1d8ed9bcff9a 41792b8f38a049bb850fd8df93900f80 3159117f7e954df9b9726ec0331cfe89--41792b8f38a049bb850fd8df93900f80 0bf0e56e921e4b68ad3382f222ad86b0 3 34c39bf8830b44f4b4073296b064e64a RX(theta₂) 41792b8f38a049bb850fd8df93900f80--34c39bf8830b44f4b4073296b064e64a 1c2f9c994f9b42b3a973761c3aa2255c RY(theta₆) 34c39bf8830b44f4b4073296b064e64a--1c2f9c994f9b42b3a973761c3aa2255c 5a6f3325935149fca6b6872d3e13dc0c RX(theta₁₀) 1c2f9c994f9b42b3a973761c3aa2255c--5a6f3325935149fca6b6872d3e13dc0c d920cd4a11cf4dc3805127ba3d1bfd8b 5a6f3325935149fca6b6872d3e13dc0c--d920cd4a11cf4dc3805127ba3d1bfd8b 917ef4b618d14d32befc427ba92f747e X d920cd4a11cf4dc3805127ba3d1bfd8b--917ef4b618d14d32befc427ba92f747e 917ef4b618d14d32befc427ba92f747e--e6d84a2e31a44324bf47f0b6d3f783a9 f8612a74563c49138333f0a555c363d3 RX(theta₁₄) 917ef4b618d14d32befc427ba92f747e--f8612a74563c49138333f0a555c363d3 034de624e3b34d56b32e892a922b82b1 RY(theta₁₈) f8612a74563c49138333f0a555c363d3--034de624e3b34d56b32e892a922b82b1 71ac2377a81e4f20a47888289f27d797 RX(theta₂₂) 034de624e3b34d56b32e892a922b82b1--71ac2377a81e4f20a47888289f27d797 9fee2dc5e6614258be025cceaa5f6e67 71ac2377a81e4f20a47888289f27d797--9fee2dc5e6614258be025cceaa5f6e67 b4d5237e39eb4fa1a9068322941a5f99 X 9fee2dc5e6614258be025cceaa5f6e67--b4d5237e39eb4fa1a9068322941a5f99 b4d5237e39eb4fa1a9068322941a5f99--3daa71f3231b454cbb8a29f0761a9f91 b4d5237e39eb4fa1a9068322941a5f99--36e2f7b5444b45a18e1b1d8ed9bcff9a 1586e50e822f48948f5e7bfec9199619 52cff28c003345a2a5fb6ee04852e231 X 0bf0e56e921e4b68ad3382f222ad86b0--52cff28c003345a2a5fb6ee04852e231 7eada622819645148fe1f63cc3534c86 RX(theta₃) 52cff28c003345a2a5fb6ee04852e231--7eada622819645148fe1f63cc3534c86 a1e1c575176c4f6f9e0907a499920b7d RY(theta₇) 7eada622819645148fe1f63cc3534c86--a1e1c575176c4f6f9e0907a499920b7d f6a5162268d7451c970981fade4f9158 RX(theta₁₁) a1e1c575176c4f6f9e0907a499920b7d--f6a5162268d7451c970981fade4f9158 e3b7b892acc9493d80826d686293de65 X f6a5162268d7451c970981fade4f9158--e3b7b892acc9493d80826d686293de65 e3b7b892acc9493d80826d686293de65--d920cd4a11cf4dc3805127ba3d1bfd8b 566065c3f2194659ae84ebb84c63fe74 e3b7b892acc9493d80826d686293de65--566065c3f2194659ae84ebb84c63fe74 a56459e5d1174328b5041cda8318cad5 RX(theta₁₅) 566065c3f2194659ae84ebb84c63fe74--a56459e5d1174328b5041cda8318cad5 92fce19e7b24440b8fa20e52b4206bbc RY(theta₁₉) a56459e5d1174328b5041cda8318cad5--92fce19e7b24440b8fa20e52b4206bbc 093a06862b464b128e69eaa1eca19958 RX(theta₂₃) 92fce19e7b24440b8fa20e52b4206bbc--093a06862b464b128e69eaa1eca19958 b6eaf966a1ad4b13997a5e4209eec8c0 X 093a06862b464b128e69eaa1eca19958--b6eaf966a1ad4b13997a5e4209eec8c0 b6eaf966a1ad4b13997a5e4209eec8c0--9fee2dc5e6614258be025cceaa5f6e67 4d657692bd38460ab90bc2980f46f78d b6eaf966a1ad4b13997a5e4209eec8c0--4d657692bd38460ab90bc2980f46f78d 4d657692bd38460ab90bc2980f46f78d--1586e50e822f48948f5e7bfec9199619
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]])

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, 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.1175-0.1590j, -0.0951+0.4807j,  0.3795+0.1401j,  0.0923-0.0757j,
         -0.0139+0.0967j,  0.2482-0.4274j,  0.0270+0.0782j,  0.1034-0.5211j],
        [ 0.4179-0.0928j,  0.0479+0.2284j,  0.4056-0.1999j, -0.0744+0.2450j,
          0.3361+0.2284j,  0.1638+0.4372j, -0.3177+0.0341j, -0.0824+0.0170j]])

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