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.79208433+0.j         0.        -0.60645514j 0.05509328+0.j
 0.        -0.04218188j]

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_4343d04be70f4add8fa3709e7f611342 Circuit block cluster_7c12db6761a84231b842f335b93ffacc Prep block 0fd4f2abc2474a5aae9f452c4a51b68e 0 f1a0652c0c134d8e996bdb8326f534fb 0fd4f2abc2474a5aae9f452c4a51b68e--f1a0652c0c134d8e996bdb8326f534fb a4f45ca72e7d4e5881edbad69e9a832f 1 5d9adc1aa2f7491993f1c43650e6c370 RX(theta₀) f1a0652c0c134d8e996bdb8326f534fb--5d9adc1aa2f7491993f1c43650e6c370 b4cdae3d90a64b1f92a1c16d7052001d RY(theta₄) 5d9adc1aa2f7491993f1c43650e6c370--b4cdae3d90a64b1f92a1c16d7052001d 5455ba37f94247fc84fabaf1ac93c881 RX(theta₈) b4cdae3d90a64b1f92a1c16d7052001d--5455ba37f94247fc84fabaf1ac93c881 781eba2f774c4ecea27c9ec68754256e 5455ba37f94247fc84fabaf1ac93c881--781eba2f774c4ecea27c9ec68754256e 44cdec9e3bb543188c8c053589634a02 781eba2f774c4ecea27c9ec68754256e--44cdec9e3bb543188c8c053589634a02 2760852f9e8d4536903940578f388772 RX(theta₁₂) 44cdec9e3bb543188c8c053589634a02--2760852f9e8d4536903940578f388772 8fd850c0e19b42c28f07a357feb446fd RY(theta₁₆) 2760852f9e8d4536903940578f388772--8fd850c0e19b42c28f07a357feb446fd 913363912c254860817af199a097f6b8 RX(theta₂₀) 8fd850c0e19b42c28f07a357feb446fd--913363912c254860817af199a097f6b8 4c36659680e0496aaa7b65fb85f0958b 913363912c254860817af199a097f6b8--4c36659680e0496aaa7b65fb85f0958b 18cd7ae382524431ae6f8db06bc69e3e 4c36659680e0496aaa7b65fb85f0958b--18cd7ae382524431ae6f8db06bc69e3e 567ac9bf057c487fbd00d217acbaccba 18cd7ae382524431ae6f8db06bc69e3e--567ac9bf057c487fbd00d217acbaccba 8814984c711041879b8731559839f0f1 391afb18319d4363896f03ae67939bb3 a4f45ca72e7d4e5881edbad69e9a832f--391afb18319d4363896f03ae67939bb3 b29abbe6129744cf9e5b8c1bb316ebba 2 43e0d7b742bf4448a5c16e9e67f6940a RX(theta₁) 391afb18319d4363896f03ae67939bb3--43e0d7b742bf4448a5c16e9e67f6940a f3b71a687a1c41e5be2558e48541617c RY(theta₅) 43e0d7b742bf4448a5c16e9e67f6940a--f3b71a687a1c41e5be2558e48541617c 165d6632bd2340a5b21156106a054c60 RX(theta₉) f3b71a687a1c41e5be2558e48541617c--165d6632bd2340a5b21156106a054c60 9384720532fb41c8bff6d66c437ce9c0 X 165d6632bd2340a5b21156106a054c60--9384720532fb41c8bff6d66c437ce9c0 9384720532fb41c8bff6d66c437ce9c0--781eba2f774c4ecea27c9ec68754256e b2805ac0b9a04b93bb8edf87b5e0cf14 9384720532fb41c8bff6d66c437ce9c0--b2805ac0b9a04b93bb8edf87b5e0cf14 67055bc259ac4ba19eb694b78528a203 RX(theta₁₃) b2805ac0b9a04b93bb8edf87b5e0cf14--67055bc259ac4ba19eb694b78528a203 a6f26acc7b7d47aa8feee183901bd43d RY(theta₁₇) 67055bc259ac4ba19eb694b78528a203--a6f26acc7b7d47aa8feee183901bd43d 3efd9287bfa642ddae82801f347a0eb8 RX(theta₂₁) a6f26acc7b7d47aa8feee183901bd43d--3efd9287bfa642ddae82801f347a0eb8 3a2814b8fd2748559626f2884c33955b X 3efd9287bfa642ddae82801f347a0eb8--3a2814b8fd2748559626f2884c33955b 3a2814b8fd2748559626f2884c33955b--4c36659680e0496aaa7b65fb85f0958b c981c157f47f4458a181fcd33afb9e8d 3a2814b8fd2748559626f2884c33955b--c981c157f47f4458a181fcd33afb9e8d c981c157f47f4458a181fcd33afb9e8d--8814984c711041879b8731559839f0f1 4d8945db3e04447bbf2956d741439fbe ecae63b7fd054b3f945f342053ed6303 b29abbe6129744cf9e5b8c1bb316ebba--ecae63b7fd054b3f945f342053ed6303 20ab3b165a87404793813b4099042080 3 03c9efec996544d894be913eed4f1ca9 RX(theta₂) ecae63b7fd054b3f945f342053ed6303--03c9efec996544d894be913eed4f1ca9 8dae96c2314a4ef29a937c140ff9291d RY(theta₆) 03c9efec996544d894be913eed4f1ca9--8dae96c2314a4ef29a937c140ff9291d c006839f2bc940648bc04229108ac252 RX(theta₁₀) 8dae96c2314a4ef29a937c140ff9291d--c006839f2bc940648bc04229108ac252 e848b8369b944eb0876fb5829968675b c006839f2bc940648bc04229108ac252--e848b8369b944eb0876fb5829968675b fea3f910556c4af582c0fbafaf485b25 X e848b8369b944eb0876fb5829968675b--fea3f910556c4af582c0fbafaf485b25 fea3f910556c4af582c0fbafaf485b25--b2805ac0b9a04b93bb8edf87b5e0cf14 786e8c75943d4e69bba1621ec3f32dd4 RX(theta₁₄) fea3f910556c4af582c0fbafaf485b25--786e8c75943d4e69bba1621ec3f32dd4 5da338df919a4ff49a4c1b35e92af7ed RY(theta₁₈) 786e8c75943d4e69bba1621ec3f32dd4--5da338df919a4ff49a4c1b35e92af7ed a50efbcdafe74177b2b8a2466191a6c9 RX(theta₂₂) 5da338df919a4ff49a4c1b35e92af7ed--a50efbcdafe74177b2b8a2466191a6c9 6de93a0046d84a67a715216ffd1d8070 a50efbcdafe74177b2b8a2466191a6c9--6de93a0046d84a67a715216ffd1d8070 32b410d4d0554c78afe149660cf9f93d X 6de93a0046d84a67a715216ffd1d8070--32b410d4d0554c78afe149660cf9f93d 32b410d4d0554c78afe149660cf9f93d--c981c157f47f4458a181fcd33afb9e8d 32b410d4d0554c78afe149660cf9f93d--4d8945db3e04447bbf2956d741439fbe 748146fe0c3a4dd190d6bb746e85c147 b53c5f0b22c74a51a2e06140f393ae1c X 20ab3b165a87404793813b4099042080--b53c5f0b22c74a51a2e06140f393ae1c a2e076e3b1224cb296465c3bb87b483d RX(theta₃) b53c5f0b22c74a51a2e06140f393ae1c--a2e076e3b1224cb296465c3bb87b483d 79a4e8ec70c94bc3bbff97ced73aa14f RY(theta₇) a2e076e3b1224cb296465c3bb87b483d--79a4e8ec70c94bc3bbff97ced73aa14f 79a0c1e16326418a937596bd62ece4bc RX(theta₁₁) 79a4e8ec70c94bc3bbff97ced73aa14f--79a0c1e16326418a937596bd62ece4bc f76cae0798b847b0ba1915d260747602 X 79a0c1e16326418a937596bd62ece4bc--f76cae0798b847b0ba1915d260747602 f76cae0798b847b0ba1915d260747602--e848b8369b944eb0876fb5829968675b 17346c9da73145b7bf34d1b3ed8cceb8 f76cae0798b847b0ba1915d260747602--17346c9da73145b7bf34d1b3ed8cceb8 1e8282159b804c4e9aabf1cc8a65fe7b RX(theta₁₅) 17346c9da73145b7bf34d1b3ed8cceb8--1e8282159b804c4e9aabf1cc8a65fe7b 345517e529564299bb7fa435dda7ab0b RY(theta₁₉) 1e8282159b804c4e9aabf1cc8a65fe7b--345517e529564299bb7fa435dda7ab0b 9e9f78c50b4e47c29febfcd874baa04c RX(theta₂₃) 345517e529564299bb7fa435dda7ab0b--9e9f78c50b4e47c29febfcd874baa04c 8a6a85946df14a25962b7350fe6c6ddf X 9e9f78c50b4e47c29febfcd874baa04c--8a6a85946df14a25962b7350fe6c6ddf 8a6a85946df14a25962b7350fe6c6ddf--6de93a0046d84a67a715216ffd1d8070 3ea9155c021749dab5ece55901af8211 8a6a85946df14a25962b7350fe6c6ddf--3ea9155c021749dab5ece55901af8211 3ea9155c021749dab5ece55901af8211--748146fe0c3a4dd190d6bb746e85c147
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, 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]])

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.0072+0.1317j, -0.1315+0.0093j,  0.4393-0.0518j,  0.2144-0.0019j,
         -0.4913+0.3684j, -0.0079-0.3988j, -0.0065-0.0633j, -0.2841+0.3202j],
        [-0.2017-0.2458j,  0.3581-0.0040j, -0.0432+0.3556j, -0.0084-0.1461j,
          0.2217+0.1800j,  0.5418+0.0416j, -0.3747-0.3151j,  0.0661+0.0052j]])

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