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.58924015+0.j          0.        -0.0426862j   0.        -0.80472075j
 -0.05829621+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_4371b66b571f4a0fa32624dfb13a681b Circuit block cluster_f53e550314d94f8b891451b86a8d33b1 Prep block e6bd7fa9f3c1456db4de097910828292 0 0a0ff1590d4d4c4696a14b04b13caee7 e6bd7fa9f3c1456db4de097910828292--0a0ff1590d4d4c4696a14b04b13caee7 03a781df9b1b49b7a17796241258a264 1 55434fa14d5f4697b20ce34138b492e9 RX(theta₀) 0a0ff1590d4d4c4696a14b04b13caee7--55434fa14d5f4697b20ce34138b492e9 9ab694b570c54b95ae7188795976042a RY(theta₄) 55434fa14d5f4697b20ce34138b492e9--9ab694b570c54b95ae7188795976042a f1edc04159e64c26aa9b7295e6a5ef4c RX(theta₈) 9ab694b570c54b95ae7188795976042a--f1edc04159e64c26aa9b7295e6a5ef4c 30f659f47efa4ebd9fb30d46d6038916 f1edc04159e64c26aa9b7295e6a5ef4c--30f659f47efa4ebd9fb30d46d6038916 96dec0507cc241818a36c936093c478f 30f659f47efa4ebd9fb30d46d6038916--96dec0507cc241818a36c936093c478f 915db6578b8c4cc28d3f2f1771d16c6f RX(theta₁₂) 96dec0507cc241818a36c936093c478f--915db6578b8c4cc28d3f2f1771d16c6f 5bfc0329f03346dfb0b1998f6ecc8c63 RY(theta₁₆) 915db6578b8c4cc28d3f2f1771d16c6f--5bfc0329f03346dfb0b1998f6ecc8c63 b1d9562f144c43c5b5b7bd702cd692cf RX(theta₂₀) 5bfc0329f03346dfb0b1998f6ecc8c63--b1d9562f144c43c5b5b7bd702cd692cf b264521002914d72a6d0e58a06344c0f b1d9562f144c43c5b5b7bd702cd692cf--b264521002914d72a6d0e58a06344c0f 2eed1b06b9d74658b2f8044b99b6076e b264521002914d72a6d0e58a06344c0f--2eed1b06b9d74658b2f8044b99b6076e cccd94736b274bd7960b7c162a9261a1 2eed1b06b9d74658b2f8044b99b6076e--cccd94736b274bd7960b7c162a9261a1 e363a2695c39471d95fa9251ab736008 217c4ae19dbe4aa2bf091fb4dff8a301 03a781df9b1b49b7a17796241258a264--217c4ae19dbe4aa2bf091fb4dff8a301 a563bb0cfda74f5b9b0de2c732888d29 2 993d4da1806046db82714345716f34be RX(theta₁) 217c4ae19dbe4aa2bf091fb4dff8a301--993d4da1806046db82714345716f34be 2499c952b2624850b99018725eb016b4 RY(theta₅) 993d4da1806046db82714345716f34be--2499c952b2624850b99018725eb016b4 59a4eee851e943c9974b2cf9ef7ee151 RX(theta₉) 2499c952b2624850b99018725eb016b4--59a4eee851e943c9974b2cf9ef7ee151 a9fec30b378544c0a462bd01ca509fcd X 59a4eee851e943c9974b2cf9ef7ee151--a9fec30b378544c0a462bd01ca509fcd a9fec30b378544c0a462bd01ca509fcd--30f659f47efa4ebd9fb30d46d6038916 4cf2855b23fe4d42a9f66ceaa76046a4 a9fec30b378544c0a462bd01ca509fcd--4cf2855b23fe4d42a9f66ceaa76046a4 898f68360380448b994cd51f04e83463 RX(theta₁₃) 4cf2855b23fe4d42a9f66ceaa76046a4--898f68360380448b994cd51f04e83463 2b82fb9daf2b444a9d49b7923308ba59 RY(theta₁₇) 898f68360380448b994cd51f04e83463--2b82fb9daf2b444a9d49b7923308ba59 9027bf8b38bf4e6c834a2e71c1b45b6e RX(theta₂₁) 2b82fb9daf2b444a9d49b7923308ba59--9027bf8b38bf4e6c834a2e71c1b45b6e 0395b231ac424588b35a8f7fa06aa8de X 9027bf8b38bf4e6c834a2e71c1b45b6e--0395b231ac424588b35a8f7fa06aa8de 0395b231ac424588b35a8f7fa06aa8de--b264521002914d72a6d0e58a06344c0f 0e9f00cb16764e50a8169faaa393f789 0395b231ac424588b35a8f7fa06aa8de--0e9f00cb16764e50a8169faaa393f789 0e9f00cb16764e50a8169faaa393f789--e363a2695c39471d95fa9251ab736008 2fc6aec3961e45f4a19f17112580a235 1ff8627ae73d4daa8ef97b7fd5413445 a563bb0cfda74f5b9b0de2c732888d29--1ff8627ae73d4daa8ef97b7fd5413445 d8fc1b1188fb40299aef6e3f6679331d 3 0a13694d268649e3b6e5a991a8b0b151 RX(theta₂) 1ff8627ae73d4daa8ef97b7fd5413445--0a13694d268649e3b6e5a991a8b0b151 10dae30ce6ef4a2d879f20210cda28c8 RY(theta₆) 0a13694d268649e3b6e5a991a8b0b151--10dae30ce6ef4a2d879f20210cda28c8 05d3c9a7ab2242c0970238d0c987f26b RX(theta₁₀) 10dae30ce6ef4a2d879f20210cda28c8--05d3c9a7ab2242c0970238d0c987f26b 83f4b21207ee481a92b883647a3f22f6 05d3c9a7ab2242c0970238d0c987f26b--83f4b21207ee481a92b883647a3f22f6 c71f958469f944a984dafb224e779398 X 83f4b21207ee481a92b883647a3f22f6--c71f958469f944a984dafb224e779398 c71f958469f944a984dafb224e779398--4cf2855b23fe4d42a9f66ceaa76046a4 55b651b1c4a54cf791f32131e24e616f RX(theta₁₄) c71f958469f944a984dafb224e779398--55b651b1c4a54cf791f32131e24e616f a050786800984d1b8ba48f797b5ef111 RY(theta₁₈) 55b651b1c4a54cf791f32131e24e616f--a050786800984d1b8ba48f797b5ef111 d8496713dea249e89da60c47d67b1c5d RX(theta₂₂) a050786800984d1b8ba48f797b5ef111--d8496713dea249e89da60c47d67b1c5d 1dec7cde1dd94cad952f0782cc0cee5b d8496713dea249e89da60c47d67b1c5d--1dec7cde1dd94cad952f0782cc0cee5b 29c3a5f3b81f463a976515ca74362825 X 1dec7cde1dd94cad952f0782cc0cee5b--29c3a5f3b81f463a976515ca74362825 29c3a5f3b81f463a976515ca74362825--0e9f00cb16764e50a8169faaa393f789 29c3a5f3b81f463a976515ca74362825--2fc6aec3961e45f4a19f17112580a235 cf84e52736b447158aedc289a35dfccc 915cbd73e2e848a0b2f36adf61bc1d5b X d8fc1b1188fb40299aef6e3f6679331d--915cbd73e2e848a0b2f36adf61bc1d5b 8748963e84f04011a861e53f09da032c RX(theta₃) 915cbd73e2e848a0b2f36adf61bc1d5b--8748963e84f04011a861e53f09da032c f4bdc3cf384946388489677884046e7a RY(theta₇) 8748963e84f04011a861e53f09da032c--f4bdc3cf384946388489677884046e7a 0d95ce9b839041059829021ceabab932 RX(theta₁₁) f4bdc3cf384946388489677884046e7a--0d95ce9b839041059829021ceabab932 a2584959d1324c17bd37a7ecdf6702df X 0d95ce9b839041059829021ceabab932--a2584959d1324c17bd37a7ecdf6702df a2584959d1324c17bd37a7ecdf6702df--83f4b21207ee481a92b883647a3f22f6 13d4c85b32c547a7ba604a3fb4260b4b a2584959d1324c17bd37a7ecdf6702df--13d4c85b32c547a7ba604a3fb4260b4b 683b4d14df5d45ae8306b885f4739cca RX(theta₁₅) 13d4c85b32c547a7ba604a3fb4260b4b--683b4d14df5d45ae8306b885f4739cca ecd8bebd76db4942bcc02eef82ac018f RY(theta₁₉) 683b4d14df5d45ae8306b885f4739cca--ecd8bebd76db4942bcc02eef82ac018f f337cc8373e24817af6a1d530da62e5d RX(theta₂₃) ecd8bebd76db4942bcc02eef82ac018f--f337cc8373e24817af6a1d530da62e5d 20d510c941e342b2a0ae0b9c299d5443 X f337cc8373e24817af6a1d530da62e5d--20d510c941e342b2a0ae0b9c299d5443 20d510c941e342b2a0ae0b9c299d5443--1dec7cde1dd94cad952f0782cc0cee5b 8d190481b36f4578a37392a24fac397a 20d510c941e342b2a0ae0b9c299d5443--8d190481b36f4578a37392a24fac397a 8d190481b36f4578a37392a24fac397a--cf84e52736b447158aedc289a35dfccc
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, 1.+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.2081+0.2344j, -0.1377-0.1414j,  0.0648+0.0879j,  0.2784+0.3919j,
         -0.3448-0.2388j,  0.1042-0.0920j,  0.1097-0.3815j,  0.5086+0.0908j],
        [ 0.1926-0.1005j,  0.1366-0.2113j,  0.3341+0.0283j,  0.4666-0.0519j,
         -0.0352-0.1661j,  0.1113-0.1136j, -0.5330+0.3841j,  0.1875+0.1890j]])

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