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.09573453-0.9954069j 0.        +0.j        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_3de77a67644d4105ac98fa64342a15a3 Circuit block cluster_67a64a38358c47079cab219d209041b4 Prep block d4b7821d6f5b4e7db6edc0155868df25 0 33c9d7a12eab4260adbbdfe51a4347c0 d4b7821d6f5b4e7db6edc0155868df25--33c9d7a12eab4260adbbdfe51a4347c0 8b7eb1f9bcad446a95adb09988cec23c 1 5779ab83efac4bc9b5a6345cf2f43fcc RX(theta₀) 33c9d7a12eab4260adbbdfe51a4347c0--5779ab83efac4bc9b5a6345cf2f43fcc bb2448fadc06461292079f367da45cc7 RY(theta₄) 5779ab83efac4bc9b5a6345cf2f43fcc--bb2448fadc06461292079f367da45cc7 71750456dcef470f90f46a729808637c RX(theta₈) bb2448fadc06461292079f367da45cc7--71750456dcef470f90f46a729808637c 53e46d67d383428fb0a8e7d5d9b1a534 71750456dcef470f90f46a729808637c--53e46d67d383428fb0a8e7d5d9b1a534 4104fa1a69874264b36bb02eba801eb0 53e46d67d383428fb0a8e7d5d9b1a534--4104fa1a69874264b36bb02eba801eb0 df41fa98f8ca4161b05b72cc5b016cc4 RX(theta₁₂) 4104fa1a69874264b36bb02eba801eb0--df41fa98f8ca4161b05b72cc5b016cc4 800f7c32646e439cac571738f233bc6b RY(theta₁₆) df41fa98f8ca4161b05b72cc5b016cc4--800f7c32646e439cac571738f233bc6b 542f24b3fd1d443c94300ac196b093ca RX(theta₂₀) 800f7c32646e439cac571738f233bc6b--542f24b3fd1d443c94300ac196b093ca dbdd71b338af4a1bb89b12b90c0ba4e5 542f24b3fd1d443c94300ac196b093ca--dbdd71b338af4a1bb89b12b90c0ba4e5 3c3c496516d84e9db60a201de4838e6a dbdd71b338af4a1bb89b12b90c0ba4e5--3c3c496516d84e9db60a201de4838e6a 66699e4525444a18a5c878f5f4941bca 3c3c496516d84e9db60a201de4838e6a--66699e4525444a18a5c878f5f4941bca 0be9a1d4569f4d2a9e2058b7460f3f08 77d6419237664f37a357af2fbd5daa8a 8b7eb1f9bcad446a95adb09988cec23c--77d6419237664f37a357af2fbd5daa8a c07f563c93d34bc7be0777d30a8a44d3 2 701affa5f20f4d63844a474e69a63f23 RX(theta₁) 77d6419237664f37a357af2fbd5daa8a--701affa5f20f4d63844a474e69a63f23 c7ee152c3a4e45cc81161584906f0c16 RY(theta₅) 701affa5f20f4d63844a474e69a63f23--c7ee152c3a4e45cc81161584906f0c16 897012ca02ae4e24b41ae30edadf42a2 RX(theta₉) c7ee152c3a4e45cc81161584906f0c16--897012ca02ae4e24b41ae30edadf42a2 2a22edec0c0947269571b77b2062d867 X 897012ca02ae4e24b41ae30edadf42a2--2a22edec0c0947269571b77b2062d867 2a22edec0c0947269571b77b2062d867--53e46d67d383428fb0a8e7d5d9b1a534 747920d2c1a147969916b1ae299cb0f3 2a22edec0c0947269571b77b2062d867--747920d2c1a147969916b1ae299cb0f3 57060540824142e08c2dbfea962b6466 RX(theta₁₃) 747920d2c1a147969916b1ae299cb0f3--57060540824142e08c2dbfea962b6466 9a5fabe90695421b8ed6e87e602f8a08 RY(theta₁₇) 57060540824142e08c2dbfea962b6466--9a5fabe90695421b8ed6e87e602f8a08 9218f12971254f0f9080d5a819b52e83 RX(theta₂₁) 9a5fabe90695421b8ed6e87e602f8a08--9218f12971254f0f9080d5a819b52e83 666ed3e8167c4731adf980da73cedd05 X 9218f12971254f0f9080d5a819b52e83--666ed3e8167c4731adf980da73cedd05 666ed3e8167c4731adf980da73cedd05--dbdd71b338af4a1bb89b12b90c0ba4e5 446e99050f5548cc94f1824ca6f981df 666ed3e8167c4731adf980da73cedd05--446e99050f5548cc94f1824ca6f981df 446e99050f5548cc94f1824ca6f981df--0be9a1d4569f4d2a9e2058b7460f3f08 3ca2235bdfbd4177a614c71c58196701 309da3c4756b4cbcba2f8bb0c25fc69c c07f563c93d34bc7be0777d30a8a44d3--309da3c4756b4cbcba2f8bb0c25fc69c 03c1eb036a044425ba6b7f21cbbc4765 3 69c3cebef3954af3b38f323022d6a643 RX(theta₂) 309da3c4756b4cbcba2f8bb0c25fc69c--69c3cebef3954af3b38f323022d6a643 2090c9c347c740e8a333f3d528cc1288 RY(theta₆) 69c3cebef3954af3b38f323022d6a643--2090c9c347c740e8a333f3d528cc1288 c318b607f62f447681e2a0ab0d9ab2d4 RX(theta₁₀) 2090c9c347c740e8a333f3d528cc1288--c318b607f62f447681e2a0ab0d9ab2d4 6ca12fa3f3294cefab0abe2ceda6e785 c318b607f62f447681e2a0ab0d9ab2d4--6ca12fa3f3294cefab0abe2ceda6e785 055b00e778a3414dba840d5a667bba2d X 6ca12fa3f3294cefab0abe2ceda6e785--055b00e778a3414dba840d5a667bba2d 055b00e778a3414dba840d5a667bba2d--747920d2c1a147969916b1ae299cb0f3 e9aae1dbe2f04190ba472685f46c386e RX(theta₁₄) 055b00e778a3414dba840d5a667bba2d--e9aae1dbe2f04190ba472685f46c386e c81313fe288340338abeb5749e182bcd RY(theta₁₈) e9aae1dbe2f04190ba472685f46c386e--c81313fe288340338abeb5749e182bcd c5d341da95be48afa67052bc83be0507 RX(theta₂₂) c81313fe288340338abeb5749e182bcd--c5d341da95be48afa67052bc83be0507 e260e1622e1b487fa29c77fb7d43adbb c5d341da95be48afa67052bc83be0507--e260e1622e1b487fa29c77fb7d43adbb ca213fd5be514beebf02cdbc854c39ac X e260e1622e1b487fa29c77fb7d43adbb--ca213fd5be514beebf02cdbc854c39ac ca213fd5be514beebf02cdbc854c39ac--446e99050f5548cc94f1824ca6f981df ca213fd5be514beebf02cdbc854c39ac--3ca2235bdfbd4177a614c71c58196701 503be18a74c74662a49c5c32d8deb575 1ffada0a7eb7450b802b066426610cda X 03c1eb036a044425ba6b7f21cbbc4765--1ffada0a7eb7450b802b066426610cda 3750ad05c4314af2850c79deb4420eda RX(theta₃) 1ffada0a7eb7450b802b066426610cda--3750ad05c4314af2850c79deb4420eda 839cf81a5e714aa78b97de7786d16234 RY(theta₇) 3750ad05c4314af2850c79deb4420eda--839cf81a5e714aa78b97de7786d16234 1db055bf32244110a5bd5f9911b7b54c RX(theta₁₁) 839cf81a5e714aa78b97de7786d16234--1db055bf32244110a5bd5f9911b7b54c 4b0eec023e4443ae8d403afec4a5f89b X 1db055bf32244110a5bd5f9911b7b54c--4b0eec023e4443ae8d403afec4a5f89b 4b0eec023e4443ae8d403afec4a5f89b--6ca12fa3f3294cefab0abe2ceda6e785 012acfa364684e798b1753130be973ce 4b0eec023e4443ae8d403afec4a5f89b--012acfa364684e798b1753130be973ce 237cc420448645648cbe032f08e14f17 RX(theta₁₅) 012acfa364684e798b1753130be973ce--237cc420448645648cbe032f08e14f17 79f3392fab1b49f6951a24aea3aae4fc RY(theta₁₉) 237cc420448645648cbe032f08e14f17--79f3392fab1b49f6951a24aea3aae4fc c40653847eaa48fdb007c0640a05334b RX(theta₂₃) 79f3392fab1b49f6951a24aea3aae4fc--c40653847eaa48fdb007c0640a05334b 3fe06d00f8ae41f582c704de4695eb5f X c40653847eaa48fdb007c0640a05334b--3fe06d00f8ae41f582c704de4695eb5f 3fe06d00f8ae41f582c704de4695eb5f--e260e1622e1b487fa29c77fb7d43adbb 853568f893b64cada1d13bea1cfcb065 3fe06d00f8ae41f582c704de4695eb5f--853568f893b64cada1d13bea1cfcb065 853568f893b64cada1d13bea1cfcb065--503be18a74c74662a49c5c32d8deb575
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.1174-0.2038j,  0.1194+0.0970j,  0.4173-0.3010j,  0.0464-0.0913j,
          0.1557-0.1457j,  0.3139+0.2603j,  0.1850+0.1393j, -0.6106-0.0869j],
        [ 0.1436-0.4136j, -0.0725+0.1590j,  0.1971-0.0148j, -0.0967-0.0249j,
         -0.3791-0.4295j,  0.1268-0.0350j, -0.3676-0.0611j,  0.1942-0.4546j]])

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