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.65634205+0.j -0.66770083+0.j -0.24624557+0.j  0.25050714+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_ccd90cedff37425a8adc40e2f75f20ef Circuit block cluster_7da7592c5bd245e58e0ec45efdeb28c7 Prep block 9fa97f011c1d4f5aa21aa200504751b4 0 7144b62fb9b9449c9487a5119c356483 9fa97f011c1d4f5aa21aa200504751b4--7144b62fb9b9449c9487a5119c356483 3d94cc2873154f368711b867d5ac3956 1 c218c9ba3dbd4c6d9883ecdb034db1e9 RX(theta₀) 7144b62fb9b9449c9487a5119c356483--c218c9ba3dbd4c6d9883ecdb034db1e9 4878e4ef1b9242d7886fca417ec189f8 RY(theta₄) c218c9ba3dbd4c6d9883ecdb034db1e9--4878e4ef1b9242d7886fca417ec189f8 537dbe74cd4b4fa2baba90643955d689 RX(theta₈) 4878e4ef1b9242d7886fca417ec189f8--537dbe74cd4b4fa2baba90643955d689 7ab76ffcd50942b886dddd24f752d8fe 537dbe74cd4b4fa2baba90643955d689--7ab76ffcd50942b886dddd24f752d8fe d301ecbf676e451e9cb0033e4e38ea11 7ab76ffcd50942b886dddd24f752d8fe--d301ecbf676e451e9cb0033e4e38ea11 81486de531a0497c8616a791c513cdcc RX(theta₁₂) d301ecbf676e451e9cb0033e4e38ea11--81486de531a0497c8616a791c513cdcc 1375542c964941f2a24059f8a1bbee4e RY(theta₁₆) 81486de531a0497c8616a791c513cdcc--1375542c964941f2a24059f8a1bbee4e c1189a8dae4f4d28a2168e0f88fa88eb RX(theta₂₀) 1375542c964941f2a24059f8a1bbee4e--c1189a8dae4f4d28a2168e0f88fa88eb 78a39259b5254794b2e685d7b921ac41 c1189a8dae4f4d28a2168e0f88fa88eb--78a39259b5254794b2e685d7b921ac41 22926004f5fa47a59d8badd11e7073b7 78a39259b5254794b2e685d7b921ac41--22926004f5fa47a59d8badd11e7073b7 e1a291d557ca4fdcb64abd78e1919640 22926004f5fa47a59d8badd11e7073b7--e1a291d557ca4fdcb64abd78e1919640 8ead09137df44204bb0ccec089f5db5f b26bf1cefd5444c494e308849d81abe8 3d94cc2873154f368711b867d5ac3956--b26bf1cefd5444c494e308849d81abe8 4ec60ec7f956424fb1077a152406d3d5 2 b4e67592771e404faf5202ab34669cef RX(theta₁) b26bf1cefd5444c494e308849d81abe8--b4e67592771e404faf5202ab34669cef 8d141b7739864181abf4eebcead545d6 RY(theta₅) b4e67592771e404faf5202ab34669cef--8d141b7739864181abf4eebcead545d6 7ed0502a39f14cb49c17f298fccf9f52 RX(theta₉) 8d141b7739864181abf4eebcead545d6--7ed0502a39f14cb49c17f298fccf9f52 c7674878131b475dad1b11fe0d7c3804 X 7ed0502a39f14cb49c17f298fccf9f52--c7674878131b475dad1b11fe0d7c3804 c7674878131b475dad1b11fe0d7c3804--7ab76ffcd50942b886dddd24f752d8fe f05cbbdb0bd2426fa0ac0f7b4e6a12c9 c7674878131b475dad1b11fe0d7c3804--f05cbbdb0bd2426fa0ac0f7b4e6a12c9 1e8e0e81921f4bac97dce730405d1c28 RX(theta₁₃) f05cbbdb0bd2426fa0ac0f7b4e6a12c9--1e8e0e81921f4bac97dce730405d1c28 692a893bb36e44c1a3e34eab5dc9f27d RY(theta₁₇) 1e8e0e81921f4bac97dce730405d1c28--692a893bb36e44c1a3e34eab5dc9f27d ea7b3e6b45444f7c91173d6b6c7fc426 RX(theta₂₁) 692a893bb36e44c1a3e34eab5dc9f27d--ea7b3e6b45444f7c91173d6b6c7fc426 79cec9126b034468aaa0d9b38d9c0542 X ea7b3e6b45444f7c91173d6b6c7fc426--79cec9126b034468aaa0d9b38d9c0542 79cec9126b034468aaa0d9b38d9c0542--78a39259b5254794b2e685d7b921ac41 cd3e3c9ddf574cb99ccf36b0c8cda8e9 79cec9126b034468aaa0d9b38d9c0542--cd3e3c9ddf574cb99ccf36b0c8cda8e9 cd3e3c9ddf574cb99ccf36b0c8cda8e9--8ead09137df44204bb0ccec089f5db5f 979e58eb3e3a4611a023b1479a6b90d0 d344f8157a8c4e3b811085ffc18595f1 4ec60ec7f956424fb1077a152406d3d5--d344f8157a8c4e3b811085ffc18595f1 e15eeb2a902243399069b5b5964d72f4 3 77a2a81f71f440278824cc227d1c1d65 RX(theta₂) d344f8157a8c4e3b811085ffc18595f1--77a2a81f71f440278824cc227d1c1d65 99d4a953e3ae4414b012e231432a4a86 RY(theta₆) 77a2a81f71f440278824cc227d1c1d65--99d4a953e3ae4414b012e231432a4a86 24384a377c014928a04bd6663001cece RX(theta₁₀) 99d4a953e3ae4414b012e231432a4a86--24384a377c014928a04bd6663001cece a9d75322a49f433aaa95c37aaeff8b61 24384a377c014928a04bd6663001cece--a9d75322a49f433aaa95c37aaeff8b61 3b18c4d2a0b645deac6ca34f9a051838 X a9d75322a49f433aaa95c37aaeff8b61--3b18c4d2a0b645deac6ca34f9a051838 3b18c4d2a0b645deac6ca34f9a051838--f05cbbdb0bd2426fa0ac0f7b4e6a12c9 caff9a01331a40c99ac678baf4d260fc RX(theta₁₄) 3b18c4d2a0b645deac6ca34f9a051838--caff9a01331a40c99ac678baf4d260fc 1bad4b117036489193bc5a6a8e8ced81 RY(theta₁₈) caff9a01331a40c99ac678baf4d260fc--1bad4b117036489193bc5a6a8e8ced81 7f1d47e3e4d34fb7ab062041d8d2034a RX(theta₂₂) 1bad4b117036489193bc5a6a8e8ced81--7f1d47e3e4d34fb7ab062041d8d2034a a5446cf095a74bec9b19a929c52c049e 7f1d47e3e4d34fb7ab062041d8d2034a--a5446cf095a74bec9b19a929c52c049e 850a200a12ff4add8ebfc392622ceba1 X a5446cf095a74bec9b19a929c52c049e--850a200a12ff4add8ebfc392622ceba1 850a200a12ff4add8ebfc392622ceba1--cd3e3c9ddf574cb99ccf36b0c8cda8e9 850a200a12ff4add8ebfc392622ceba1--979e58eb3e3a4611a023b1479a6b90d0 5d949eb37ab64a758225a66450ed0704 3f334fd32ddc4c10a69e1728dc77f0fb X e15eeb2a902243399069b5b5964d72f4--3f334fd32ddc4c10a69e1728dc77f0fb 8bdbdf4746744154ab897de757b53a78 RX(theta₃) 3f334fd32ddc4c10a69e1728dc77f0fb--8bdbdf4746744154ab897de757b53a78 c64504872d1d41d192a072fa505c1c22 RY(theta₇) 8bdbdf4746744154ab897de757b53a78--c64504872d1d41d192a072fa505c1c22 03fe3f97d90948c8ae0fa2926997fd02 RX(theta₁₁) c64504872d1d41d192a072fa505c1c22--03fe3f97d90948c8ae0fa2926997fd02 7d5cc2cf011d459aac4d61a4c1897267 X 03fe3f97d90948c8ae0fa2926997fd02--7d5cc2cf011d459aac4d61a4c1897267 7d5cc2cf011d459aac4d61a4c1897267--a9d75322a49f433aaa95c37aaeff8b61 f75dd560f7cb49ceb8eacab70db2a71e 7d5cc2cf011d459aac4d61a4c1897267--f75dd560f7cb49ceb8eacab70db2a71e b557849a245343d0a48ca5b8bb7d49bf RX(theta₁₅) f75dd560f7cb49ceb8eacab70db2a71e--b557849a245343d0a48ca5b8bb7d49bf cdfe1e17ca964850826121bf881390b4 RY(theta₁₉) b557849a245343d0a48ca5b8bb7d49bf--cdfe1e17ca964850826121bf881390b4 cb91a63466ad49a4b0d71ae26f6dc85d RX(theta₂₃) cdfe1e17ca964850826121bf881390b4--cb91a63466ad49a4b0d71ae26f6dc85d b307da20f5824c4691fb94c024d1ed51 X cb91a63466ad49a4b0d71ae26f6dc85d--b307da20f5824c4691fb94c024d1ed51 b307da20f5824c4691fb94c024d1ed51--a5446cf095a74bec9b19a929c52c049e 173797292ac04b59aca3e2cb5992a59a b307da20f5824c4691fb94c024d1ed51--173797292ac04b59aca3e2cb5992a59a 173797292ac04b59aca3e2cb5992a59a--5d949eb37ab64a758225a66450ed0704
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, 1.+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]])

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.1413-0.0314j,  0.4271+0.0558j,  0.1211-0.0650j, -0.2887-0.3458j,
          0.1520-0.5908j, -0.2196-0.1824j,  0.0992-0.2272j,  0.2243+0.0795j],
        [ 0.3506+0.1673j,  0.0850-0.2147j, -0.0631+0.6737j,  0.0306+0.2123j,
          0.3492+0.2833j,  0.0531-0.1610j,  0.1590-0.0134j,  0.1670+0.0875j]])

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