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.68785575+0.j -0.51406525+0.j  0.41047196+0.j -0.30676399+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_8cf8fb16a14149378cbec5d16865b363 Circuit block cluster_ad0dac2cef4c4549a5586a4384692058 Prep block 7f138431d3c14a3eb58a2332a15fed11 0 06b69e3bfee140779a927d2f1b0acb99 7f138431d3c14a3eb58a2332a15fed11--06b69e3bfee140779a927d2f1b0acb99 4c1d47c7e73a452fbd22a3fba246cbca 1 1ddacfd27e6c48e8ba5bf655d622a91f RX(theta₀) 06b69e3bfee140779a927d2f1b0acb99--1ddacfd27e6c48e8ba5bf655d622a91f 9f77cfde37b644d5bf294f10471f7626 RY(theta₄) 1ddacfd27e6c48e8ba5bf655d622a91f--9f77cfde37b644d5bf294f10471f7626 d8087bb14bfc4844aac811274c706694 RX(theta₈) 9f77cfde37b644d5bf294f10471f7626--d8087bb14bfc4844aac811274c706694 e549833f9faf4758a58b0670871b0b08 d8087bb14bfc4844aac811274c706694--e549833f9faf4758a58b0670871b0b08 0e696fef94d84b10aa61e90cd4f1a043 e549833f9faf4758a58b0670871b0b08--0e696fef94d84b10aa61e90cd4f1a043 b1653682f1a64945a831c838459f860c RX(theta₁₂) 0e696fef94d84b10aa61e90cd4f1a043--b1653682f1a64945a831c838459f860c 4a0a7913e626434f936fca3863fe24c4 RY(theta₁₆) b1653682f1a64945a831c838459f860c--4a0a7913e626434f936fca3863fe24c4 c650222c818e4252a05dd2666cf89975 RX(theta₂₀) 4a0a7913e626434f936fca3863fe24c4--c650222c818e4252a05dd2666cf89975 448cf69d7a7e40c784543ec9c5c1f08e c650222c818e4252a05dd2666cf89975--448cf69d7a7e40c784543ec9c5c1f08e 61b4c8da1baa4fc088f54b331e123559 448cf69d7a7e40c784543ec9c5c1f08e--61b4c8da1baa4fc088f54b331e123559 e24ebaa03d7f4c20a78201fdcc2baa0a 61b4c8da1baa4fc088f54b331e123559--e24ebaa03d7f4c20a78201fdcc2baa0a 621ba43619504e928995fbb0e4b8c7b9 94631a567c8f4f93a558f22d962b5f89 4c1d47c7e73a452fbd22a3fba246cbca--94631a567c8f4f93a558f22d962b5f89 487d3fc6262f465f83af8a9be18531e1 2 c8827908620541a8af23534f11f42858 RX(theta₁) 94631a567c8f4f93a558f22d962b5f89--c8827908620541a8af23534f11f42858 d5f2e04a8b824b9e8c7bdf3d2b695a0c RY(theta₅) c8827908620541a8af23534f11f42858--d5f2e04a8b824b9e8c7bdf3d2b695a0c 8178e13f70cf428eab8732121b6cda69 RX(theta₉) d5f2e04a8b824b9e8c7bdf3d2b695a0c--8178e13f70cf428eab8732121b6cda69 7092507b60e34ccf9d184e1af06943c4 X 8178e13f70cf428eab8732121b6cda69--7092507b60e34ccf9d184e1af06943c4 7092507b60e34ccf9d184e1af06943c4--e549833f9faf4758a58b0670871b0b08 78335dd98a1047e688a894b841534522 7092507b60e34ccf9d184e1af06943c4--78335dd98a1047e688a894b841534522 ca4961eaced64c898b234ef739e48e58 RX(theta₁₃) 78335dd98a1047e688a894b841534522--ca4961eaced64c898b234ef739e48e58 c8463c8eaa35439da3c03b18e56ad00f RY(theta₁₇) ca4961eaced64c898b234ef739e48e58--c8463c8eaa35439da3c03b18e56ad00f a962c27b06954a02b9ad39dbb3e536b5 RX(theta₂₁) c8463c8eaa35439da3c03b18e56ad00f--a962c27b06954a02b9ad39dbb3e536b5 2d1d340105db4a28be931f1d09ea0c99 X a962c27b06954a02b9ad39dbb3e536b5--2d1d340105db4a28be931f1d09ea0c99 2d1d340105db4a28be931f1d09ea0c99--448cf69d7a7e40c784543ec9c5c1f08e a5dac2563d3f4cacb5bd5d08b8900d53 2d1d340105db4a28be931f1d09ea0c99--a5dac2563d3f4cacb5bd5d08b8900d53 a5dac2563d3f4cacb5bd5d08b8900d53--621ba43619504e928995fbb0e4b8c7b9 960328f06dfd4ec1b803ecad0d9596b1 584c71e99a7b4ac094a347f6716d190c 487d3fc6262f465f83af8a9be18531e1--584c71e99a7b4ac094a347f6716d190c 203161bb83934d5888c7e0c4546dfd0a 3 5ce0c4a2bce64e12afaeaa9d1d12105d RX(theta₂) 584c71e99a7b4ac094a347f6716d190c--5ce0c4a2bce64e12afaeaa9d1d12105d 3b88dae7dee64b1f9bb749cae4ccc8f0 RY(theta₆) 5ce0c4a2bce64e12afaeaa9d1d12105d--3b88dae7dee64b1f9bb749cae4ccc8f0 b53969a9e04e41769175725ed4c27266 RX(theta₁₀) 3b88dae7dee64b1f9bb749cae4ccc8f0--b53969a9e04e41769175725ed4c27266 a1c01692f2a84d6fa2aee38a2ccac63a b53969a9e04e41769175725ed4c27266--a1c01692f2a84d6fa2aee38a2ccac63a 806d8c09eb58408c825d4fbf6aba907d X a1c01692f2a84d6fa2aee38a2ccac63a--806d8c09eb58408c825d4fbf6aba907d 806d8c09eb58408c825d4fbf6aba907d--78335dd98a1047e688a894b841534522 ff9018367e3b46488359550946cc3543 RX(theta₁₄) 806d8c09eb58408c825d4fbf6aba907d--ff9018367e3b46488359550946cc3543 80315d79cfa34c0ca8baefce1e94af70 RY(theta₁₈) ff9018367e3b46488359550946cc3543--80315d79cfa34c0ca8baefce1e94af70 468bf1e11ffd4576aa047d515fdbaedb RX(theta₂₂) 80315d79cfa34c0ca8baefce1e94af70--468bf1e11ffd4576aa047d515fdbaedb 566993fd47c842a18f064a9440b73778 468bf1e11ffd4576aa047d515fdbaedb--566993fd47c842a18f064a9440b73778 f5fc2e8e5f0047e3a593806fb568c30e X 566993fd47c842a18f064a9440b73778--f5fc2e8e5f0047e3a593806fb568c30e f5fc2e8e5f0047e3a593806fb568c30e--a5dac2563d3f4cacb5bd5d08b8900d53 f5fc2e8e5f0047e3a593806fb568c30e--960328f06dfd4ec1b803ecad0d9596b1 236a6c690e884967a00b6ccdd1a5f092 9d0ecae2dff14b17af84cbf91c2ea968 X 203161bb83934d5888c7e0c4546dfd0a--9d0ecae2dff14b17af84cbf91c2ea968 756333a55cdc42089feb33bd01d0bce5 RX(theta₃) 9d0ecae2dff14b17af84cbf91c2ea968--756333a55cdc42089feb33bd01d0bce5 9a9b33a2445d4bf8b069d9fa1a565e0d RY(theta₇) 756333a55cdc42089feb33bd01d0bce5--9a9b33a2445d4bf8b069d9fa1a565e0d 4b95995493904d58b5c56c8a1ed086dc RX(theta₁₁) 9a9b33a2445d4bf8b069d9fa1a565e0d--4b95995493904d58b5c56c8a1ed086dc 8f1fb51131a64b9e92a3dc2adc81666f X 4b95995493904d58b5c56c8a1ed086dc--8f1fb51131a64b9e92a3dc2adc81666f 8f1fb51131a64b9e92a3dc2adc81666f--a1c01692f2a84d6fa2aee38a2ccac63a a944156010114d1ea53c7b53a6c5aa0e 8f1fb51131a64b9e92a3dc2adc81666f--a944156010114d1ea53c7b53a6c5aa0e c2d71e1cd3a14084b591ef9f1ad29624 RX(theta₁₅) a944156010114d1ea53c7b53a6c5aa0e--c2d71e1cd3a14084b591ef9f1ad29624 fc1e46bf94d84995a61c880ab050ed66 RY(theta₁₉) c2d71e1cd3a14084b591ef9f1ad29624--fc1e46bf94d84995a61c880ab050ed66 e7ce233f6d8043a1aa16f0e8102aa650 RX(theta₂₃) fc1e46bf94d84995a61c880ab050ed66--e7ce233f6d8043a1aa16f0e8102aa650 dc65c05a8f824467abee9b4caf5140dc X e7ce233f6d8043a1aa16f0e8102aa650--dc65c05a8f824467abee9b4caf5140dc dc65c05a8f824467abee9b4caf5140dc--566993fd47c842a18f064a9440b73778 1a0387bf8f3c4a81871f4d796556832d dc65c05a8f824467abee9b4caf5140dc--1a0387bf8f3c4a81871f4d796556832d 1a0387bf8f3c4a81871f4d796556832d--236a6c690e884967a00b6ccdd1a5f092
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, 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, 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.1343+0.1411j, -0.1404-0.0388j,  0.6885-0.1144j, -0.0959-0.1422j,
         -0.1421-0.1117j, -0.0652+0.1798j,  0.1188+0.0980j, -0.3975+0.4163j],
        [ 0.0151+0.3091j,  0.5099-0.1773j,  0.2565+0.2227j, -0.0893-0.3264j,
         -0.4148+0.0463j,  0.2270+0.1741j, -0.2717+0.1207j, -0.1037-0.1665j]])

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