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.4016671 +0.43579074j -0.54587946-0.59225467j  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_62976969a46f457cb8c9667c9a84b41d Circuit block cluster_3282ce8eb5ac4363b18f4825570c9ced Prep block 520ffe9ae72846b7a7e56d375e424503 0 ca61a2a77c3145d2b764eadf52418157 520ffe9ae72846b7a7e56d375e424503--ca61a2a77c3145d2b764eadf52418157 af9bdf3af9d6439283a1fc37cb57c107 1 fc04d72076744d1ca201937f3e2d96a3 RX(theta₀) ca61a2a77c3145d2b764eadf52418157--fc04d72076744d1ca201937f3e2d96a3 d43572e168c4417499c2173fa59440b0 RY(theta₄) fc04d72076744d1ca201937f3e2d96a3--d43572e168c4417499c2173fa59440b0 557bf28e2a114d009d04ccee053161d5 RX(theta₈) d43572e168c4417499c2173fa59440b0--557bf28e2a114d009d04ccee053161d5 80836a7929ef40649b6e6a38b019e5c2 557bf28e2a114d009d04ccee053161d5--80836a7929ef40649b6e6a38b019e5c2 2b9f5cc6a5574f7399b1cb961792dadb 80836a7929ef40649b6e6a38b019e5c2--2b9f5cc6a5574f7399b1cb961792dadb 9048c2c6830446fb9f5dfc6dc104245d RX(theta₁₂) 2b9f5cc6a5574f7399b1cb961792dadb--9048c2c6830446fb9f5dfc6dc104245d a79ff9670e1b4644a9a1605c8921585d RY(theta₁₆) 9048c2c6830446fb9f5dfc6dc104245d--a79ff9670e1b4644a9a1605c8921585d f298602aeef14038a52c1acd1b4aabf0 RX(theta₂₀) a79ff9670e1b4644a9a1605c8921585d--f298602aeef14038a52c1acd1b4aabf0 a75b6551fb5d467d92fec991962923e4 f298602aeef14038a52c1acd1b4aabf0--a75b6551fb5d467d92fec991962923e4 46243ac4f8f4432c96a50dd6d28fb96e a75b6551fb5d467d92fec991962923e4--46243ac4f8f4432c96a50dd6d28fb96e 6579697e53504fef8eb75d1b66963c3f 46243ac4f8f4432c96a50dd6d28fb96e--6579697e53504fef8eb75d1b66963c3f b6e80c2b95444f6da55cdf8d0d88025b 42c89fcf4299450ea6b35124badafd07 af9bdf3af9d6439283a1fc37cb57c107--42c89fcf4299450ea6b35124badafd07 53120add01484919a4c8d72679ead5d2 2 5b86c9f90ce84aae95f125136219577d RX(theta₁) 42c89fcf4299450ea6b35124badafd07--5b86c9f90ce84aae95f125136219577d e364e82336a7465192a7e3ab1a594b3c RY(theta₅) 5b86c9f90ce84aae95f125136219577d--e364e82336a7465192a7e3ab1a594b3c 494af2f3954b4233995363ff4052d098 RX(theta₉) e364e82336a7465192a7e3ab1a594b3c--494af2f3954b4233995363ff4052d098 cf7853cd07ac469e9ba620d13e956deb X 494af2f3954b4233995363ff4052d098--cf7853cd07ac469e9ba620d13e956deb cf7853cd07ac469e9ba620d13e956deb--80836a7929ef40649b6e6a38b019e5c2 0c3e975d38804006adefd520ad1a9310 cf7853cd07ac469e9ba620d13e956deb--0c3e975d38804006adefd520ad1a9310 65a7d705e5ad455ebffc7ef77ca3b409 RX(theta₁₃) 0c3e975d38804006adefd520ad1a9310--65a7d705e5ad455ebffc7ef77ca3b409 b68d11bc21e246a3bc2c5527d40a0c57 RY(theta₁₇) 65a7d705e5ad455ebffc7ef77ca3b409--b68d11bc21e246a3bc2c5527d40a0c57 879f20f90a7a4e02be58dd18e54ee8cf RX(theta₂₁) b68d11bc21e246a3bc2c5527d40a0c57--879f20f90a7a4e02be58dd18e54ee8cf fce5c0ac5f854531b3ce2d7aa2801748 X 879f20f90a7a4e02be58dd18e54ee8cf--fce5c0ac5f854531b3ce2d7aa2801748 fce5c0ac5f854531b3ce2d7aa2801748--a75b6551fb5d467d92fec991962923e4 d51e3c448e8c422f9155340053443d32 fce5c0ac5f854531b3ce2d7aa2801748--d51e3c448e8c422f9155340053443d32 d51e3c448e8c422f9155340053443d32--b6e80c2b95444f6da55cdf8d0d88025b 414276f3367c4c39beaa33c010da691e a4b8a6e4a2cc48ffa1d99a22be7bcce2 53120add01484919a4c8d72679ead5d2--a4b8a6e4a2cc48ffa1d99a22be7bcce2 3569ee43101c40f793edd301d87843b3 3 eae76bb3602647d89f53a0659ed6aad6 RX(theta₂) a4b8a6e4a2cc48ffa1d99a22be7bcce2--eae76bb3602647d89f53a0659ed6aad6 a8acebb0e769428e87ba5032b44a8334 RY(theta₆) eae76bb3602647d89f53a0659ed6aad6--a8acebb0e769428e87ba5032b44a8334 eab833ef951c40febc5ea35f00b00c5b RX(theta₁₀) a8acebb0e769428e87ba5032b44a8334--eab833ef951c40febc5ea35f00b00c5b 4f20c8ac6e8c47079295acef2a00e20f eab833ef951c40febc5ea35f00b00c5b--4f20c8ac6e8c47079295acef2a00e20f 75720122ef9f4e29aeed6f50fb981139 X 4f20c8ac6e8c47079295acef2a00e20f--75720122ef9f4e29aeed6f50fb981139 75720122ef9f4e29aeed6f50fb981139--0c3e975d38804006adefd520ad1a9310 edc80f16b1184c8698708a08b5cbbd62 RX(theta₁₄) 75720122ef9f4e29aeed6f50fb981139--edc80f16b1184c8698708a08b5cbbd62 2c93c568e670429b9414894a638ea853 RY(theta₁₈) edc80f16b1184c8698708a08b5cbbd62--2c93c568e670429b9414894a638ea853 2065544662fb42e28130b78c9896876d RX(theta₂₂) 2c93c568e670429b9414894a638ea853--2065544662fb42e28130b78c9896876d 23afd58b0fb54efeab47910a7762bd75 2065544662fb42e28130b78c9896876d--23afd58b0fb54efeab47910a7762bd75 beeef22982d440a3894b4a7ad11a102f X 23afd58b0fb54efeab47910a7762bd75--beeef22982d440a3894b4a7ad11a102f beeef22982d440a3894b4a7ad11a102f--d51e3c448e8c422f9155340053443d32 beeef22982d440a3894b4a7ad11a102f--414276f3367c4c39beaa33c010da691e 25938321e16c4e12a460edff9a5132b6 e60ac74de6134bbaa507d4adab915d62 X 3569ee43101c40f793edd301d87843b3--e60ac74de6134bbaa507d4adab915d62 b848bb0152d347d99208b145f5877f41 RX(theta₃) e60ac74de6134bbaa507d4adab915d62--b848bb0152d347d99208b145f5877f41 eabafc91d5c3407a9fe21ea0052e292c RY(theta₇) b848bb0152d347d99208b145f5877f41--eabafc91d5c3407a9fe21ea0052e292c 56f6124e81394f3d823a1e2c1eaf3de1 RX(theta₁₁) eabafc91d5c3407a9fe21ea0052e292c--56f6124e81394f3d823a1e2c1eaf3de1 4132f0dfe9ab4b69881aa974845d919f X 56f6124e81394f3d823a1e2c1eaf3de1--4132f0dfe9ab4b69881aa974845d919f 4132f0dfe9ab4b69881aa974845d919f--4f20c8ac6e8c47079295acef2a00e20f 3a108d86fc054c509a41c2a97a17fc61 4132f0dfe9ab4b69881aa974845d919f--3a108d86fc054c509a41c2a97a17fc61 5f0066ecf3b34eaebd077a32568ba838 RX(theta₁₅) 3a108d86fc054c509a41c2a97a17fc61--5f0066ecf3b34eaebd077a32568ba838 89370ef86a534222b42d8e8ff315940e RY(theta₁₉) 5f0066ecf3b34eaebd077a32568ba838--89370ef86a534222b42d8e8ff315940e 013bf075fa0e43709dc19535987abf11 RX(theta₂₃) 89370ef86a534222b42d8e8ff315940e--013bf075fa0e43709dc19535987abf11 7c04f9d986b34efb92879c50c6a88bb1 X 013bf075fa0e43709dc19535987abf11--7c04f9d986b34efb92879c50c6a88bb1 7c04f9d986b34efb92879c50c6a88bb1--23afd58b0fb54efeab47910a7762bd75 1bacefda4ac641e09461030c98b68cbb 7c04f9d986b34efb92879c50c6a88bb1--1bacefda4ac641e09461030c98b68cbb 1bacefda4ac641e09461030c98b68cbb--25938321e16c4e12a460edff9a5132b6
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, 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, 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.2390-0.1881j,  0.1646-0.0699j, -0.4417-0.1439j, -0.1631+0.1908j,
          0.0305-0.2692j,  0.2547+0.0842j,  0.1633+0.2059j, -0.2162-0.5792j],
        [ 0.0061+0.1679j,  0.1055+0.2131j, -0.1951-0.0451j,  0.0293+0.2837j,
         -0.1773+0.3076j, -0.0885+0.0918j,  0.4380+0.4700j, -0.3802+0.3070j]])

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