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.79164745-0.54544776j  0.        +0.j         -0.15618742-0.22668601j
  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_ea5c15a8aa54404a95524daf93d192f4 Circuit block cluster_d3b67ad93abd4c9ea399e87bb7a285aa Prep block 3918917c47b64279a709991e1974c225 0 58254b4548fc4f36b7f97fc5ac6fb345 3918917c47b64279a709991e1974c225--58254b4548fc4f36b7f97fc5ac6fb345 440d52368ad247189d9f00953c8b7521 1 6375746971e748858c5986f1d1c60379 RX(theta₀) 58254b4548fc4f36b7f97fc5ac6fb345--6375746971e748858c5986f1d1c60379 75aad47921aa4b99b187cf6d01630875 RY(theta₄) 6375746971e748858c5986f1d1c60379--75aad47921aa4b99b187cf6d01630875 d3c4d8aa410546d3a4d63a5ec9267220 RX(theta₈) 75aad47921aa4b99b187cf6d01630875--d3c4d8aa410546d3a4d63a5ec9267220 1de6dda3e52541a0b7817fb20eb0f102 d3c4d8aa410546d3a4d63a5ec9267220--1de6dda3e52541a0b7817fb20eb0f102 88fd6c6025114aa785ab2a7de5a18cd0 1de6dda3e52541a0b7817fb20eb0f102--88fd6c6025114aa785ab2a7de5a18cd0 63a0958a878e469caf3196f85b77f91f RX(theta₁₂) 88fd6c6025114aa785ab2a7de5a18cd0--63a0958a878e469caf3196f85b77f91f 54be111fefc44c888dbb62648b1f5f6a RY(theta₁₆) 63a0958a878e469caf3196f85b77f91f--54be111fefc44c888dbb62648b1f5f6a a04de8aaa1ef4527873f7a006c0e757d RX(theta₂₀) 54be111fefc44c888dbb62648b1f5f6a--a04de8aaa1ef4527873f7a006c0e757d f193331bd40d4832a6a36daf8de1bce5 a04de8aaa1ef4527873f7a006c0e757d--f193331bd40d4832a6a36daf8de1bce5 6078151cb5274070a33ef601a1d0248e f193331bd40d4832a6a36daf8de1bce5--6078151cb5274070a33ef601a1d0248e b28f5062737344c69e714d3cf4fbd296 6078151cb5274070a33ef601a1d0248e--b28f5062737344c69e714d3cf4fbd296 793081db098840d6b70a8287489b0593 325e8627acf54563a81df65d7cce4a80 440d52368ad247189d9f00953c8b7521--325e8627acf54563a81df65d7cce4a80 b2ab49f763054cdfa9a853405b91a2c7 2 1ab96113e3454870a388e591ea72887e RX(theta₁) 325e8627acf54563a81df65d7cce4a80--1ab96113e3454870a388e591ea72887e 84ec3cdf1de04f00b6f94aba6637cc12 RY(theta₅) 1ab96113e3454870a388e591ea72887e--84ec3cdf1de04f00b6f94aba6637cc12 689dba56ab3a4380b1fa14c4c60e2df7 RX(theta₉) 84ec3cdf1de04f00b6f94aba6637cc12--689dba56ab3a4380b1fa14c4c60e2df7 2503abaf09814a89b05627ca1684f31b X 689dba56ab3a4380b1fa14c4c60e2df7--2503abaf09814a89b05627ca1684f31b 2503abaf09814a89b05627ca1684f31b--1de6dda3e52541a0b7817fb20eb0f102 908356aa0c2745e3a5820d6ed0848ae0 2503abaf09814a89b05627ca1684f31b--908356aa0c2745e3a5820d6ed0848ae0 c0ba1c0d839c43e68d85716f5ffe6f56 RX(theta₁₃) 908356aa0c2745e3a5820d6ed0848ae0--c0ba1c0d839c43e68d85716f5ffe6f56 0bcc9a67969847208cd0a94cf5cb3f3c RY(theta₁₇) c0ba1c0d839c43e68d85716f5ffe6f56--0bcc9a67969847208cd0a94cf5cb3f3c 0f2b85da415548a985e037f7cfcdcdbb RX(theta₂₁) 0bcc9a67969847208cd0a94cf5cb3f3c--0f2b85da415548a985e037f7cfcdcdbb f8b6d808e2b84046b38d3121b80b0453 X 0f2b85da415548a985e037f7cfcdcdbb--f8b6d808e2b84046b38d3121b80b0453 f8b6d808e2b84046b38d3121b80b0453--f193331bd40d4832a6a36daf8de1bce5 beaccafeab954dc8ac33794f2bfb8ae7 f8b6d808e2b84046b38d3121b80b0453--beaccafeab954dc8ac33794f2bfb8ae7 beaccafeab954dc8ac33794f2bfb8ae7--793081db098840d6b70a8287489b0593 77e231de30414ae59f023dc02d3cb6cc 70254aab020d4b3ea563ef4f59ef3b98 b2ab49f763054cdfa9a853405b91a2c7--70254aab020d4b3ea563ef4f59ef3b98 e40215454af8461ea64bf3bcf5d91c31 3 a3f24652b87b40bc808b511aa485183c RX(theta₂) 70254aab020d4b3ea563ef4f59ef3b98--a3f24652b87b40bc808b511aa485183c ba08b44dc7ce40cab2844d3ac2e979f3 RY(theta₆) a3f24652b87b40bc808b511aa485183c--ba08b44dc7ce40cab2844d3ac2e979f3 580053b2625448e4a71ffcad2e095785 RX(theta₁₀) ba08b44dc7ce40cab2844d3ac2e979f3--580053b2625448e4a71ffcad2e095785 c9c4086b78a4484c8d2ee1ccebd948e8 580053b2625448e4a71ffcad2e095785--c9c4086b78a4484c8d2ee1ccebd948e8 95a9c513003e48ebaa8104fc5b14d77c X c9c4086b78a4484c8d2ee1ccebd948e8--95a9c513003e48ebaa8104fc5b14d77c 95a9c513003e48ebaa8104fc5b14d77c--908356aa0c2745e3a5820d6ed0848ae0 c102b718c6f749188cdf162357510f89 RX(theta₁₄) 95a9c513003e48ebaa8104fc5b14d77c--c102b718c6f749188cdf162357510f89 1259469d0e5146b09a75cc276c1c523d RY(theta₁₈) c102b718c6f749188cdf162357510f89--1259469d0e5146b09a75cc276c1c523d fd7a68046d174e4ca3bdb7d041962db3 RX(theta₂₂) 1259469d0e5146b09a75cc276c1c523d--fd7a68046d174e4ca3bdb7d041962db3 7070a36812f74ee688777a2b37497c79 fd7a68046d174e4ca3bdb7d041962db3--7070a36812f74ee688777a2b37497c79 c36eac881f914103b7e9d2ce1a359292 X 7070a36812f74ee688777a2b37497c79--c36eac881f914103b7e9d2ce1a359292 c36eac881f914103b7e9d2ce1a359292--beaccafeab954dc8ac33794f2bfb8ae7 c36eac881f914103b7e9d2ce1a359292--77e231de30414ae59f023dc02d3cb6cc 58f1ad654496466e99b5df54bde48673 66d5bcc9fc41494bb5f251ead81ceffc X e40215454af8461ea64bf3bcf5d91c31--66d5bcc9fc41494bb5f251ead81ceffc 66d24a0c72fb468cbfde5b6b01d9f07e RX(theta₃) 66d5bcc9fc41494bb5f251ead81ceffc--66d24a0c72fb468cbfde5b6b01d9f07e 77f76178bccf4ebbb530db6cfeb1d5d8 RY(theta₇) 66d24a0c72fb468cbfde5b6b01d9f07e--77f76178bccf4ebbb530db6cfeb1d5d8 cb9c4c39edd9483eabf30746d9b21d25 RX(theta₁₁) 77f76178bccf4ebbb530db6cfeb1d5d8--cb9c4c39edd9483eabf30746d9b21d25 6b545a9130094920a6f80db4d119e722 X cb9c4c39edd9483eabf30746d9b21d25--6b545a9130094920a6f80db4d119e722 6b545a9130094920a6f80db4d119e722--c9c4086b78a4484c8d2ee1ccebd948e8 b36070cbd01b4b36a77257b8be70f036 6b545a9130094920a6f80db4d119e722--b36070cbd01b4b36a77257b8be70f036 bee396d800454f12a09f331bdbea66af RX(theta₁₅) b36070cbd01b4b36a77257b8be70f036--bee396d800454f12a09f331bdbea66af c276102ec3344e98a1ee210e4a4119b2 RY(theta₁₉) bee396d800454f12a09f331bdbea66af--c276102ec3344e98a1ee210e4a4119b2 5e5bc65a547b4d0d9863e5242f708a0f RX(theta₂₃) c276102ec3344e98a1ee210e4a4119b2--5e5bc65a547b4d0d9863e5242f708a0f d8886c1c96274dfe8126e895458951ab X 5e5bc65a547b4d0d9863e5242f708a0f--d8886c1c96274dfe8126e895458951ab d8886c1c96274dfe8126e895458951ab--7070a36812f74ee688777a2b37497c79 9e15d62a607c481f96afb060943059bc d8886c1c96274dfe8126e895458951ab--9e15d62a607c481f96afb060943059bc 9e15d62a607c481f96afb060943059bc--58f1ad654496466e99b5df54bde48673
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, 0.+0.j, 0.+0.j, 1.+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.2657-0.1563j, -0.1378+0.0364j, -0.0100+0.4277j, -0.0458-0.2744j,
          0.5303+0.1397j,  0.4328-0.2540j,  0.1917+0.0810j,  0.1610-0.0493j],
        [-0.1124+0.6346j,  0.0115-0.2532j,  0.0335+0.0200j, -0.3132-0.0899j,
         -0.0593+0.2424j, -0.0353-0.0099j, -0.3368+0.1502j, -0.4531-0.0885j]])

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