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.92861342+0.j  0.36763729+0.j -0.04667426+0.j -0.0184783 +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_26f18de5d7ed4abb9871b821baeb2b43 Circuit block cluster_e43706f9a848402f9e5cd8b34f44960f Prep block 2fa9dc8de9f34fb49ea27bf1387bdd40 0 a6ad8eda80604add819b50aadc0fd9d7 2fa9dc8de9f34fb49ea27bf1387bdd40--a6ad8eda80604add819b50aadc0fd9d7 aec10b8d4a594bed9f11859cf0bda35b 1 cf36fbbd800e4cdda85395d88535958d RX(theta₀) a6ad8eda80604add819b50aadc0fd9d7--cf36fbbd800e4cdda85395d88535958d b83f5d4098e246f6ba37950b6aeee2ad RY(theta₄) cf36fbbd800e4cdda85395d88535958d--b83f5d4098e246f6ba37950b6aeee2ad 57cec917e1d5475c8b01dbbbe850b9cb RX(theta₈) b83f5d4098e246f6ba37950b6aeee2ad--57cec917e1d5475c8b01dbbbe850b9cb ea462195c6364ca381cb25d37a5beced 57cec917e1d5475c8b01dbbbe850b9cb--ea462195c6364ca381cb25d37a5beced 3c3471db2a964962aec9c7c026396125 ea462195c6364ca381cb25d37a5beced--3c3471db2a964962aec9c7c026396125 604ebe925ba2494b96dffefb2d65f6f4 RX(theta₁₂) 3c3471db2a964962aec9c7c026396125--604ebe925ba2494b96dffefb2d65f6f4 4e703c8ad78c45efb0af9eb8e0c71c2c RY(theta₁₆) 604ebe925ba2494b96dffefb2d65f6f4--4e703c8ad78c45efb0af9eb8e0c71c2c 0d7331a7c3d047638ce28bc43f901369 RX(theta₂₀) 4e703c8ad78c45efb0af9eb8e0c71c2c--0d7331a7c3d047638ce28bc43f901369 67275c467d904137bcd996fc2332607c 0d7331a7c3d047638ce28bc43f901369--67275c467d904137bcd996fc2332607c edef43d14cff4b3fb8a3548a83fc9ee3 67275c467d904137bcd996fc2332607c--edef43d14cff4b3fb8a3548a83fc9ee3 0fbd22ceeef14f13886afe452ea2c578 edef43d14cff4b3fb8a3548a83fc9ee3--0fbd22ceeef14f13886afe452ea2c578 53e4940b89b4466b8f880144ef73f87d 90401d48597e4782a12601b6a7a23aa4 aec10b8d4a594bed9f11859cf0bda35b--90401d48597e4782a12601b6a7a23aa4 a70069f1501c4beb9669ced4a496a08e 2 7488ed6bc9964e32865bbe8de13436e8 RX(theta₁) 90401d48597e4782a12601b6a7a23aa4--7488ed6bc9964e32865bbe8de13436e8 8c21452d29db40f591b0a0d952c4659e RY(theta₅) 7488ed6bc9964e32865bbe8de13436e8--8c21452d29db40f591b0a0d952c4659e 7f0f71df208c4be5904bd0ffec524b90 RX(theta₉) 8c21452d29db40f591b0a0d952c4659e--7f0f71df208c4be5904bd0ffec524b90 36d3a872a400414ba5a71543fa17079c X 7f0f71df208c4be5904bd0ffec524b90--36d3a872a400414ba5a71543fa17079c 36d3a872a400414ba5a71543fa17079c--ea462195c6364ca381cb25d37a5beced 6b15107f32004303b6b8f79770ff6715 36d3a872a400414ba5a71543fa17079c--6b15107f32004303b6b8f79770ff6715 2cd9b1f9355d4272afdb90ef8bc89b46 RX(theta₁₃) 6b15107f32004303b6b8f79770ff6715--2cd9b1f9355d4272afdb90ef8bc89b46 9e92e73b735e4c49aa27833c39b467c0 RY(theta₁₇) 2cd9b1f9355d4272afdb90ef8bc89b46--9e92e73b735e4c49aa27833c39b467c0 f910552b4c7f4c8385e44abb94e5ff4c RX(theta₂₁) 9e92e73b735e4c49aa27833c39b467c0--f910552b4c7f4c8385e44abb94e5ff4c b0725e5c70524c27876d572aec41de0e X f910552b4c7f4c8385e44abb94e5ff4c--b0725e5c70524c27876d572aec41de0e b0725e5c70524c27876d572aec41de0e--67275c467d904137bcd996fc2332607c ad3597df04ef461ca2cd836d1f5347c2 b0725e5c70524c27876d572aec41de0e--ad3597df04ef461ca2cd836d1f5347c2 ad3597df04ef461ca2cd836d1f5347c2--53e4940b89b4466b8f880144ef73f87d 9d7d1c5c30a341b6ba2c340c9f3015bd 814ad8d50adb4dd3a650c8af0a95c9f7 a70069f1501c4beb9669ced4a496a08e--814ad8d50adb4dd3a650c8af0a95c9f7 7dee45c279f94cfa8009be303acce868 3 257e41edaa024b52bcba26793f0c2603 RX(theta₂) 814ad8d50adb4dd3a650c8af0a95c9f7--257e41edaa024b52bcba26793f0c2603 2daa8594c2aa4b2dbb2255231ea8ad58 RY(theta₆) 257e41edaa024b52bcba26793f0c2603--2daa8594c2aa4b2dbb2255231ea8ad58 ecd97ee9a250462990c5f9e353799ced RX(theta₁₀) 2daa8594c2aa4b2dbb2255231ea8ad58--ecd97ee9a250462990c5f9e353799ced a7a9805b008048dcb5b67de18d705fbd ecd97ee9a250462990c5f9e353799ced--a7a9805b008048dcb5b67de18d705fbd d38a48ac2003419089f3bf2d88a566b7 X a7a9805b008048dcb5b67de18d705fbd--d38a48ac2003419089f3bf2d88a566b7 d38a48ac2003419089f3bf2d88a566b7--6b15107f32004303b6b8f79770ff6715 7eb1605e72e0499c97ef8bb31c2dbe34 RX(theta₁₄) d38a48ac2003419089f3bf2d88a566b7--7eb1605e72e0499c97ef8bb31c2dbe34 8d8df817d5624f26add835b6cdce4e6d RY(theta₁₈) 7eb1605e72e0499c97ef8bb31c2dbe34--8d8df817d5624f26add835b6cdce4e6d 8de0fe047c484a0d9d40b776d96f462a RX(theta₂₂) 8d8df817d5624f26add835b6cdce4e6d--8de0fe047c484a0d9d40b776d96f462a a464fbaaaf924d5d8714639fd735f3aa 8de0fe047c484a0d9d40b776d96f462a--a464fbaaaf924d5d8714639fd735f3aa d6701d8e44374b65bce33c8b0e5613cf X a464fbaaaf924d5d8714639fd735f3aa--d6701d8e44374b65bce33c8b0e5613cf d6701d8e44374b65bce33c8b0e5613cf--ad3597df04ef461ca2cd836d1f5347c2 d6701d8e44374b65bce33c8b0e5613cf--9d7d1c5c30a341b6ba2c340c9f3015bd d615bedc690240d39cb6f48e49b3b5b3 079ef52bd33a4301bb54d00422d95b43 X 7dee45c279f94cfa8009be303acce868--079ef52bd33a4301bb54d00422d95b43 b3749076d3824179b391123261a4a867 RX(theta₃) 079ef52bd33a4301bb54d00422d95b43--b3749076d3824179b391123261a4a867 92c5b1876d424382bb40e135abdd76f3 RY(theta₇) b3749076d3824179b391123261a4a867--92c5b1876d424382bb40e135abdd76f3 a2728a9b56254a8ea9be8ab34ef48306 RX(theta₁₁) 92c5b1876d424382bb40e135abdd76f3--a2728a9b56254a8ea9be8ab34ef48306 74907c24fb294163b7e28869495f2a57 X a2728a9b56254a8ea9be8ab34ef48306--74907c24fb294163b7e28869495f2a57 74907c24fb294163b7e28869495f2a57--a7a9805b008048dcb5b67de18d705fbd 5d1b4f53695141a48f04a6313bf79c6b 74907c24fb294163b7e28869495f2a57--5d1b4f53695141a48f04a6313bf79c6b 1325e40ac3a44b39b3ae86b1bf2df8b4 RX(theta₁₅) 5d1b4f53695141a48f04a6313bf79c6b--1325e40ac3a44b39b3ae86b1bf2df8b4 58739be90b8348ba96a83ae093068e9b RY(theta₁₉) 1325e40ac3a44b39b3ae86b1bf2df8b4--58739be90b8348ba96a83ae093068e9b 28440f4e3785414f8976b089ef13a065 RX(theta₂₃) 58739be90b8348ba96a83ae093068e9b--28440f4e3785414f8976b089ef13a065 e90dc05f28e344b49f1f9458675aeced X 28440f4e3785414f8976b089ef13a065--e90dc05f28e344b49f1f9458675aeced e90dc05f28e344b49f1f9458675aeced--a464fbaaaf924d5d8714639fd735f3aa 6beb9df2063d4bc8be1e6aebe4683003 e90dc05f28e344b49f1f9458675aeced--6beb9df2063d4bc8be1e6aebe4683003 6beb9df2063d4bc8be1e6aebe4683003--d615bedc690240d39cb6f48e49b3b5b3
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, 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]])

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.4778-0.3032j, -0.2188+0.0063j, -0.5854+0.1054j, -0.0209+0.1171j,
         -0.1233+0.1146j,  0.2949-0.1529j,  0.2178+0.2514j,  0.0053+0.1206j],
        [ 0.0060+0.1147j,  0.1033+0.1432j, -0.2309+0.3088j, -0.2681+0.2402j,
         -0.2283-0.2065j, -0.4066+0.1532j, -0.5098-0.1379j,  0.2512-0.2275j]])

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