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.98111062+0.j         0.08438519+0.j         0.        +0.17343176j
 0.        +0.01491684j]

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_afaef9aac5de4cc5b28f43cb537ce0cc Circuit block cluster_75bcf2f28e6a41d1abfc0ab2ebfd0adc Prep block cfad5fcadc294a5c890ff2de256f7eef 0 2bc5769d554b4963a829848c804bbd85 cfad5fcadc294a5c890ff2de256f7eef--2bc5769d554b4963a829848c804bbd85 d43f06ebf6b049c4ac2b2e14ef66d48b 1 54fff406b4274ca4bbe0f11e6dfe7e48 RX(theta₀) 2bc5769d554b4963a829848c804bbd85--54fff406b4274ca4bbe0f11e6dfe7e48 83e4947cc3954b739bd4b5dba6b379c5 RY(theta₄) 54fff406b4274ca4bbe0f11e6dfe7e48--83e4947cc3954b739bd4b5dba6b379c5 52ed7b2424f64432be239e07cce81066 RX(theta₈) 83e4947cc3954b739bd4b5dba6b379c5--52ed7b2424f64432be239e07cce81066 9b427bd5148a4f579f874a006a2ed453 52ed7b2424f64432be239e07cce81066--9b427bd5148a4f579f874a006a2ed453 bb6476075c9545e6b1c225d8ff48e0d3 9b427bd5148a4f579f874a006a2ed453--bb6476075c9545e6b1c225d8ff48e0d3 454d41f70d2b4b06b880d405ee57ba5a RX(theta₁₂) bb6476075c9545e6b1c225d8ff48e0d3--454d41f70d2b4b06b880d405ee57ba5a c82c8b8824264114a26d5a6d2326fd22 RY(theta₁₆) 454d41f70d2b4b06b880d405ee57ba5a--c82c8b8824264114a26d5a6d2326fd22 7d19e6cc1dad476cb53c13888a953db5 RX(theta₂₀) c82c8b8824264114a26d5a6d2326fd22--7d19e6cc1dad476cb53c13888a953db5 2b91091e2a924e4ba8d916cbde4596b2 7d19e6cc1dad476cb53c13888a953db5--2b91091e2a924e4ba8d916cbde4596b2 ce02a40c557a41d18abc02da38041c31 2b91091e2a924e4ba8d916cbde4596b2--ce02a40c557a41d18abc02da38041c31 8539094df6174952a186767e778f1c91 ce02a40c557a41d18abc02da38041c31--8539094df6174952a186767e778f1c91 b4aebab4f9a44fa5aae1c08bafe99ef5 7765ad7bc2114068ab64613d74902cda d43f06ebf6b049c4ac2b2e14ef66d48b--7765ad7bc2114068ab64613d74902cda 907df7c4ea3547f78f204e516c22cda0 2 8b755f8a1b704915aff6aa8088013de1 RX(theta₁) 7765ad7bc2114068ab64613d74902cda--8b755f8a1b704915aff6aa8088013de1 97d10a74a4c840109b8a7fd403564bb9 RY(theta₅) 8b755f8a1b704915aff6aa8088013de1--97d10a74a4c840109b8a7fd403564bb9 9ada60d8e1ec4e7ea97d0ed67e40f5c9 RX(theta₉) 97d10a74a4c840109b8a7fd403564bb9--9ada60d8e1ec4e7ea97d0ed67e40f5c9 fcfa538221c346299717d2742f5632ed X 9ada60d8e1ec4e7ea97d0ed67e40f5c9--fcfa538221c346299717d2742f5632ed fcfa538221c346299717d2742f5632ed--9b427bd5148a4f579f874a006a2ed453 57413f60c0864f418782741097a1a3dd fcfa538221c346299717d2742f5632ed--57413f60c0864f418782741097a1a3dd 41d4946cfe174e81a934b3abd5450ebb RX(theta₁₃) 57413f60c0864f418782741097a1a3dd--41d4946cfe174e81a934b3abd5450ebb 1f819e87fdcf4d9eb0e29195ff5f73fe RY(theta₁₇) 41d4946cfe174e81a934b3abd5450ebb--1f819e87fdcf4d9eb0e29195ff5f73fe ec60ad5c75724f139543aea16383adcb RX(theta₂₁) 1f819e87fdcf4d9eb0e29195ff5f73fe--ec60ad5c75724f139543aea16383adcb e72acb5afc6f4b5b9117d9894ac27989 X ec60ad5c75724f139543aea16383adcb--e72acb5afc6f4b5b9117d9894ac27989 e72acb5afc6f4b5b9117d9894ac27989--2b91091e2a924e4ba8d916cbde4596b2 a970e1c4db864d09b58102d9df7e8fa5 e72acb5afc6f4b5b9117d9894ac27989--a970e1c4db864d09b58102d9df7e8fa5 a970e1c4db864d09b58102d9df7e8fa5--b4aebab4f9a44fa5aae1c08bafe99ef5 e70687a548bc4faaab8897e82682bee3 8c522278d23f45efb428a6a9b00968ce 907df7c4ea3547f78f204e516c22cda0--8c522278d23f45efb428a6a9b00968ce 85b9718d33194a7a9e74fae708e2c229 3 83f5932bce594b4cbb6a5ead5c31a3d1 RX(theta₂) 8c522278d23f45efb428a6a9b00968ce--83f5932bce594b4cbb6a5ead5c31a3d1 e6101c174949414a87094a7a38575b9a RY(theta₆) 83f5932bce594b4cbb6a5ead5c31a3d1--e6101c174949414a87094a7a38575b9a d001bb58e8614be3801a963965b48ee9 RX(theta₁₀) e6101c174949414a87094a7a38575b9a--d001bb58e8614be3801a963965b48ee9 4aefbb1e1d624edd97a42d19bac4ec88 d001bb58e8614be3801a963965b48ee9--4aefbb1e1d624edd97a42d19bac4ec88 22bd7641cab74cb5884026db2f3c17a6 X 4aefbb1e1d624edd97a42d19bac4ec88--22bd7641cab74cb5884026db2f3c17a6 22bd7641cab74cb5884026db2f3c17a6--57413f60c0864f418782741097a1a3dd 0b50d19ff84747a7a5eeac3e9086b804 RX(theta₁₄) 22bd7641cab74cb5884026db2f3c17a6--0b50d19ff84747a7a5eeac3e9086b804 b1df69d88c10455494a953c417c77b78 RY(theta₁₈) 0b50d19ff84747a7a5eeac3e9086b804--b1df69d88c10455494a953c417c77b78 17eae20d08e246358a51d3dfc964c995 RX(theta₂₂) b1df69d88c10455494a953c417c77b78--17eae20d08e246358a51d3dfc964c995 7f8ad99c7cc549bd948e872ab03dc6bf 17eae20d08e246358a51d3dfc964c995--7f8ad99c7cc549bd948e872ab03dc6bf b03d061883c44d1483b3622d0ce502f2 X 7f8ad99c7cc549bd948e872ab03dc6bf--b03d061883c44d1483b3622d0ce502f2 b03d061883c44d1483b3622d0ce502f2--a970e1c4db864d09b58102d9df7e8fa5 b03d061883c44d1483b3622d0ce502f2--e70687a548bc4faaab8897e82682bee3 c9b4a546fa8e44d1a7ff9427c2064173 322ec9ed6d284054b385636ec2623dd7 X 85b9718d33194a7a9e74fae708e2c229--322ec9ed6d284054b385636ec2623dd7 b89f62b3054648938818e1e832df73cb RX(theta₃) 322ec9ed6d284054b385636ec2623dd7--b89f62b3054648938818e1e832df73cb 777f755e02c84a048b43943c6368ef53 RY(theta₇) b89f62b3054648938818e1e832df73cb--777f755e02c84a048b43943c6368ef53 11be39d03b104af3a0bdc47fb3af7056 RX(theta₁₁) 777f755e02c84a048b43943c6368ef53--11be39d03b104af3a0bdc47fb3af7056 1a16ccc8f7b949aea3408b2021e6bc82 X 11be39d03b104af3a0bdc47fb3af7056--1a16ccc8f7b949aea3408b2021e6bc82 1a16ccc8f7b949aea3408b2021e6bc82--4aefbb1e1d624edd97a42d19bac4ec88 cc4c60bbb09b4d1f86dffeed87830200 1a16ccc8f7b949aea3408b2021e6bc82--cc4c60bbb09b4d1f86dffeed87830200 54a85eb1543442bba175957a354b35d6 RX(theta₁₅) cc4c60bbb09b4d1f86dffeed87830200--54a85eb1543442bba175957a354b35d6 bec423b730e04a26a33ed60e3a4b56c0 RY(theta₁₉) 54a85eb1543442bba175957a354b35d6--bec423b730e04a26a33ed60e3a4b56c0 f2b813e60e59486f9bb8d0b15ec3d7d3 RX(theta₂₃) bec423b730e04a26a33ed60e3a4b56c0--f2b813e60e59486f9bb8d0b15ec3d7d3 5ee1854df468423ca7b3a95ef4bf0599 X f2b813e60e59486f9bb8d0b15ec3d7d3--5ee1854df468423ca7b3a95ef4bf0599 5ee1854df468423ca7b3a95ef4bf0599--7f8ad99c7cc549bd948e872ab03dc6bf 208dfcb3ebbc4da5abf311a1526721e7 5ee1854df468423ca7b3a95ef4bf0599--208dfcb3ebbc4da5abf311a1526721e7 208dfcb3ebbc4da5abf311a1526721e7--c9b4a546fa8e44d1a7ff9427c2064173
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.1732-0.0990j,  0.2022+0.2079j, -0.1102+0.2475j, -0.2171+0.4750j,
          0.1075-0.0152j, -0.0820+0.1841j, -0.1133-0.1981j, -0.6522-0.0096j],
        [-0.0571+0.1382j, -0.6252+0.0486j,  0.2354-0.4191j, -0.0668+0.0385j,
          0.0395-0.1282j,  0.1214-0.4909j,  0.0412+0.0087j,  0.2465-0.1057j]])

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

Density matrices conversion

It is also possible to obtain density matrices from statevectors. They can be passed as inputs to quantum programs performing density matrix based operations such as noisy simulations, when the backend allows such as PyQTorch.

from qadence import product_state, density_mat

init_state = product_state("10")
init_density_matrix = density_mat(init_state)

final_density_matrix = run(CNOT(0, 1), state=init_density_matrix)
Initial = DensityMatrix([[[0.+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, 0.+0.j, 1.+0.j, 0.+0.j],
                [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]]])
Final = DensityMatrix([[[0.-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, 0.-0.j, 0.-0.j, 0.-0.j],
                [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)
└── 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]])