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.79202251+0.j         0.        +0.26684655j 0.        -0.52034457j
 0.17531339+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_b56674d6e6a64da5b93f8616afa3e368 Circuit block cluster_0b523c8911da4e65ac7279d1a0cf1469 Prep block 9e8d768b3ec64acfb6b928a1994c55e5 0 6d3f0c71ca7a41cb90dbc7528b601ead 9e8d768b3ec64acfb6b928a1994c55e5--6d3f0c71ca7a41cb90dbc7528b601ead e9ae9a4e037e4911bcd4bf20fa77cb47 1 2ad14ca759694dcbb157103b83273e08 RX(theta₀) 6d3f0c71ca7a41cb90dbc7528b601ead--2ad14ca759694dcbb157103b83273e08 ac87b065584c4b7a8cc37d0c26d14bf4 RY(theta₄) 2ad14ca759694dcbb157103b83273e08--ac87b065584c4b7a8cc37d0c26d14bf4 7ca8a60510194930908f542bb698685b RX(theta₈) ac87b065584c4b7a8cc37d0c26d14bf4--7ca8a60510194930908f542bb698685b 25fa32709fdf4151931bb51f3b41191f 7ca8a60510194930908f542bb698685b--25fa32709fdf4151931bb51f3b41191f 8377a773195f4f6ba8d30abcfa2c92e2 25fa32709fdf4151931bb51f3b41191f--8377a773195f4f6ba8d30abcfa2c92e2 1cc33a6a576d4cf78322c3c93bc96ba9 RX(theta₁₂) 8377a773195f4f6ba8d30abcfa2c92e2--1cc33a6a576d4cf78322c3c93bc96ba9 d92f635fa84d4e9386c9f95e0a78e89e RY(theta₁₆) 1cc33a6a576d4cf78322c3c93bc96ba9--d92f635fa84d4e9386c9f95e0a78e89e 347dfa6d410f41709efb3dc53723f75d RX(theta₂₀) d92f635fa84d4e9386c9f95e0a78e89e--347dfa6d410f41709efb3dc53723f75d f260cf401ab44827a8f2edce8bb06dd2 347dfa6d410f41709efb3dc53723f75d--f260cf401ab44827a8f2edce8bb06dd2 de382b17a85d4947b52c7b3986ce9c9b f260cf401ab44827a8f2edce8bb06dd2--de382b17a85d4947b52c7b3986ce9c9b 64c3e5b8ceed4a469d4079c9ec76b2be de382b17a85d4947b52c7b3986ce9c9b--64c3e5b8ceed4a469d4079c9ec76b2be d17cd55b3c704e7bac8f20447c5263ec 3e5593d4cb7347d3b4a71b7fd90403a9 e9ae9a4e037e4911bcd4bf20fa77cb47--3e5593d4cb7347d3b4a71b7fd90403a9 f884b4dbe15b4c67a799ce35b15165e2 2 36084d6dfdcc4eb19942d51542eec39d RX(theta₁) 3e5593d4cb7347d3b4a71b7fd90403a9--36084d6dfdcc4eb19942d51542eec39d 2d68eb11305b4ecc9008a5d6e1cdfdc7 RY(theta₅) 36084d6dfdcc4eb19942d51542eec39d--2d68eb11305b4ecc9008a5d6e1cdfdc7 3a8010f26a7a4ad49a6a7f88474de6e8 RX(theta₉) 2d68eb11305b4ecc9008a5d6e1cdfdc7--3a8010f26a7a4ad49a6a7f88474de6e8 1ec76017b2d84aaeb9c0b61c437254ff X 3a8010f26a7a4ad49a6a7f88474de6e8--1ec76017b2d84aaeb9c0b61c437254ff 1ec76017b2d84aaeb9c0b61c437254ff--25fa32709fdf4151931bb51f3b41191f ddcb19f38d9a4d05b64d532901607cfd 1ec76017b2d84aaeb9c0b61c437254ff--ddcb19f38d9a4d05b64d532901607cfd 00bdb882ff6248768f41cca6decebab7 RX(theta₁₃) ddcb19f38d9a4d05b64d532901607cfd--00bdb882ff6248768f41cca6decebab7 b0fa564de65b4ab082c408dc3c674e1e RY(theta₁₇) 00bdb882ff6248768f41cca6decebab7--b0fa564de65b4ab082c408dc3c674e1e 18378b3c8b7345b7a3d5547d1e770f73 RX(theta₂₁) b0fa564de65b4ab082c408dc3c674e1e--18378b3c8b7345b7a3d5547d1e770f73 e99329d2904e4601884a3062282869e7 X 18378b3c8b7345b7a3d5547d1e770f73--e99329d2904e4601884a3062282869e7 e99329d2904e4601884a3062282869e7--f260cf401ab44827a8f2edce8bb06dd2 3121e28b1e8b4bbc934895233ff7c5ca e99329d2904e4601884a3062282869e7--3121e28b1e8b4bbc934895233ff7c5ca 3121e28b1e8b4bbc934895233ff7c5ca--d17cd55b3c704e7bac8f20447c5263ec 665e0d1eb98542f7ac86e5a0d54c0a6f f610e7c656e04531a1080df2b26af5c3 f884b4dbe15b4c67a799ce35b15165e2--f610e7c656e04531a1080df2b26af5c3 d344511b0896447b910436515fbf9975 3 170f172cd7bb4b7aa03f85570e2086ad RX(theta₂) f610e7c656e04531a1080df2b26af5c3--170f172cd7bb4b7aa03f85570e2086ad bd130024149d47f6a346e4102c7ad186 RY(theta₆) 170f172cd7bb4b7aa03f85570e2086ad--bd130024149d47f6a346e4102c7ad186 956ceaac32cf426698320b83401e9aaf RX(theta₁₀) bd130024149d47f6a346e4102c7ad186--956ceaac32cf426698320b83401e9aaf 17b7606720d64948b0df873831ad696f 956ceaac32cf426698320b83401e9aaf--17b7606720d64948b0df873831ad696f 26d4a928264e4ad79b97c0c401b70ef4 X 17b7606720d64948b0df873831ad696f--26d4a928264e4ad79b97c0c401b70ef4 26d4a928264e4ad79b97c0c401b70ef4--ddcb19f38d9a4d05b64d532901607cfd 6d67c0af80884fabadf16d7e49059fc6 RX(theta₁₄) 26d4a928264e4ad79b97c0c401b70ef4--6d67c0af80884fabadf16d7e49059fc6 1c5d88663c394091836aeba78abe5fe9 RY(theta₁₈) 6d67c0af80884fabadf16d7e49059fc6--1c5d88663c394091836aeba78abe5fe9 cde517ecc6bc4f9a8ccde39ba1d38976 RX(theta₂₂) 1c5d88663c394091836aeba78abe5fe9--cde517ecc6bc4f9a8ccde39ba1d38976 c9c446644d4b48c0af92b820f5d21c4f cde517ecc6bc4f9a8ccde39ba1d38976--c9c446644d4b48c0af92b820f5d21c4f c7c325cbf2b7488c911ffd7f8e369ec2 X c9c446644d4b48c0af92b820f5d21c4f--c7c325cbf2b7488c911ffd7f8e369ec2 c7c325cbf2b7488c911ffd7f8e369ec2--3121e28b1e8b4bbc934895233ff7c5ca c7c325cbf2b7488c911ffd7f8e369ec2--665e0d1eb98542f7ac86e5a0d54c0a6f 204ddf24c80f4411a3be963cc1cbc371 cf7ff9cdcb674548869e2b8e101965b6 X d344511b0896447b910436515fbf9975--cf7ff9cdcb674548869e2b8e101965b6 a1a6b2fc034e4cfbb0108900fe3475c3 RX(theta₃) cf7ff9cdcb674548869e2b8e101965b6--a1a6b2fc034e4cfbb0108900fe3475c3 500e877aef134765ba2099f619b033d5 RY(theta₇) a1a6b2fc034e4cfbb0108900fe3475c3--500e877aef134765ba2099f619b033d5 f6c2a6553f81412c8eae1a089c0bf62b RX(theta₁₁) 500e877aef134765ba2099f619b033d5--f6c2a6553f81412c8eae1a089c0bf62b 3f6b5cecb72d4c00a7be51f8a105b46b X f6c2a6553f81412c8eae1a089c0bf62b--3f6b5cecb72d4c00a7be51f8a105b46b 3f6b5cecb72d4c00a7be51f8a105b46b--17b7606720d64948b0df873831ad696f ea8ad21807a541b69060873c74c922a3 3f6b5cecb72d4c00a7be51f8a105b46b--ea8ad21807a541b69060873c74c922a3 2e95d67cc527418aaa1a4c2499c46222 RX(theta₁₅) ea8ad21807a541b69060873c74c922a3--2e95d67cc527418aaa1a4c2499c46222 fb67bf9f046e4f88a1251bcaf5680d88 RY(theta₁₉) 2e95d67cc527418aaa1a4c2499c46222--fb67bf9f046e4f88a1251bcaf5680d88 7e000fb399714f0e8dfe63cba7eac487 RX(theta₂₃) fb67bf9f046e4f88a1251bcaf5680d88--7e000fb399714f0e8dfe63cba7eac487 2a25ddfe95424a50b6d3a6a2362d3ba3 X 7e000fb399714f0e8dfe63cba7eac487--2a25ddfe95424a50b6d3a6a2362d3ba3 2a25ddfe95424a50b6d3a6a2362d3ba3--c9c446644d4b48c0af92b820f5d21c4f 98060d994c694c2980ac8f139accaca5 2a25ddfe95424a50b6d3a6a2362d3ba3--98060d994c694c2980ac8f139accaca5 98060d994c694c2980ac8f139accaca5--204ddf24c80f4411a3be963cc1cbc371
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, 1.+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]])

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.2027-0.1964j, -0.3514-0.1442j,  0.1544-0.3021j,  0.2899+0.3444j,
          0.4650-0.2876j,  0.0324+0.3107j, -0.1282-0.1695j,  0.1280-0.0138j],
        [ 0.5771+0.2875j, -0.0638+0.2801j,  0.1174+0.2388j, -0.0277+0.1725j,
          0.0063-0.1267j, -0.1059+0.0650j, -0.0797-0.4300j, -0.4060+0.1131j]])

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