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 = [ 9.74766377e-01+0.j -2.23196158e-01+0.j -3.64528914e-03+0.j
  8.34676440e-04+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_8608be44a7104966b80cda8d5b87b586 Circuit block cluster_c3c198e6602e453a872846cef7f5b8d9 Prep block 381db8e669114ab5b35fbbea74fd5457 0 925d16c5e2d84935a83ee00e282fd62f 381db8e669114ab5b35fbbea74fd5457--925d16c5e2d84935a83ee00e282fd62f 17995c74e5824c538137741d1ef9fc74 1 1564ea52f1e04495b562289ddf9c7a8b RX(theta₀) 925d16c5e2d84935a83ee00e282fd62f--1564ea52f1e04495b562289ddf9c7a8b d9fcf8b8ce1741e9aa503bd370fa4d28 RY(theta₄) 1564ea52f1e04495b562289ddf9c7a8b--d9fcf8b8ce1741e9aa503bd370fa4d28 ae6c0731c28846a9b35389c9932532b8 RX(theta₈) d9fcf8b8ce1741e9aa503bd370fa4d28--ae6c0731c28846a9b35389c9932532b8 ba3d0caf02d74a66959c72438a4bf448 ae6c0731c28846a9b35389c9932532b8--ba3d0caf02d74a66959c72438a4bf448 9fb6bce56c1f4f53b43e99719eb0f160 ba3d0caf02d74a66959c72438a4bf448--9fb6bce56c1f4f53b43e99719eb0f160 42f3305efce941a4ac51a633bd1b1ed3 RX(theta₁₂) 9fb6bce56c1f4f53b43e99719eb0f160--42f3305efce941a4ac51a633bd1b1ed3 0aa9bacc5a90462ca21edd346509464d RY(theta₁₆) 42f3305efce941a4ac51a633bd1b1ed3--0aa9bacc5a90462ca21edd346509464d c901d4d4ed054214a84976dcd68dc3b9 RX(theta₂₀) 0aa9bacc5a90462ca21edd346509464d--c901d4d4ed054214a84976dcd68dc3b9 ecc25b4d62a340e5889de6602dec3799 c901d4d4ed054214a84976dcd68dc3b9--ecc25b4d62a340e5889de6602dec3799 b28aafde57704e5aa69a488f6669a01a ecc25b4d62a340e5889de6602dec3799--b28aafde57704e5aa69a488f6669a01a f7438661ff984dee97b8f8fb53e5928d b28aafde57704e5aa69a488f6669a01a--f7438661ff984dee97b8f8fb53e5928d aa82535e52ac46dcb2a30babd7df7345 741f32c34995463e8315fc9e39e7a521 17995c74e5824c538137741d1ef9fc74--741f32c34995463e8315fc9e39e7a521 49295c1771b44ada9c7c39cd6bc49da2 2 7d6aa4d46f754f089724bc528c79305c RX(theta₁) 741f32c34995463e8315fc9e39e7a521--7d6aa4d46f754f089724bc528c79305c 18c25122f8f64b61af248e65451e0de4 RY(theta₅) 7d6aa4d46f754f089724bc528c79305c--18c25122f8f64b61af248e65451e0de4 fc5d91f23d2d436c951dfa6e8c2342d1 RX(theta₉) 18c25122f8f64b61af248e65451e0de4--fc5d91f23d2d436c951dfa6e8c2342d1 2e596dfa8142474abdf061fddc530f19 X fc5d91f23d2d436c951dfa6e8c2342d1--2e596dfa8142474abdf061fddc530f19 2e596dfa8142474abdf061fddc530f19--ba3d0caf02d74a66959c72438a4bf448 ae7e19ea75d64e6393987fb99ea1b519 2e596dfa8142474abdf061fddc530f19--ae7e19ea75d64e6393987fb99ea1b519 be079b58b07649f08ca0f1f9b32597a1 RX(theta₁₃) ae7e19ea75d64e6393987fb99ea1b519--be079b58b07649f08ca0f1f9b32597a1 38a1dee8da6e47f28c450dae39491cbf RY(theta₁₇) be079b58b07649f08ca0f1f9b32597a1--38a1dee8da6e47f28c450dae39491cbf 05c27747912d49758565896dac05c8ea RX(theta₂₁) 38a1dee8da6e47f28c450dae39491cbf--05c27747912d49758565896dac05c8ea 784b59f6ee8c4c478faf23a465e6d446 X 05c27747912d49758565896dac05c8ea--784b59f6ee8c4c478faf23a465e6d446 784b59f6ee8c4c478faf23a465e6d446--ecc25b4d62a340e5889de6602dec3799 bd46a69cc721403aab541a79939f2863 784b59f6ee8c4c478faf23a465e6d446--bd46a69cc721403aab541a79939f2863 bd46a69cc721403aab541a79939f2863--aa82535e52ac46dcb2a30babd7df7345 b65adb48d7be458786cf3bfc300bfb2a 739c613dafa14e8cbc5d3a3b811eaffe 49295c1771b44ada9c7c39cd6bc49da2--739c613dafa14e8cbc5d3a3b811eaffe 4e1a389b6d5b4370ba1cbf0ae5a98a5b 3 8fc5bd5bc802415a897ce94c9d158d3b RX(theta₂) 739c613dafa14e8cbc5d3a3b811eaffe--8fc5bd5bc802415a897ce94c9d158d3b a57a233865f8419ab4a23f5e488d9492 RY(theta₆) 8fc5bd5bc802415a897ce94c9d158d3b--a57a233865f8419ab4a23f5e488d9492 998218bc3e584c7c9e49f61ee1198beb RX(theta₁₀) a57a233865f8419ab4a23f5e488d9492--998218bc3e584c7c9e49f61ee1198beb 7d7abdf6de984f03b4bf1acf0b33c0c3 998218bc3e584c7c9e49f61ee1198beb--7d7abdf6de984f03b4bf1acf0b33c0c3 34fdada750ef44a89d17391373a4269e X 7d7abdf6de984f03b4bf1acf0b33c0c3--34fdada750ef44a89d17391373a4269e 34fdada750ef44a89d17391373a4269e--ae7e19ea75d64e6393987fb99ea1b519 f18ed0871cc747aaad6f603ec6e2c2a6 RX(theta₁₄) 34fdada750ef44a89d17391373a4269e--f18ed0871cc747aaad6f603ec6e2c2a6 6f139d33fa7942f6a514eeaccc7f8240 RY(theta₁₈) f18ed0871cc747aaad6f603ec6e2c2a6--6f139d33fa7942f6a514eeaccc7f8240 a7c964235ff142cca7c6763a0de15a56 RX(theta₂₂) 6f139d33fa7942f6a514eeaccc7f8240--a7c964235ff142cca7c6763a0de15a56 7cf0700a556b479cbcf2690bf2aaa750 a7c964235ff142cca7c6763a0de15a56--7cf0700a556b479cbcf2690bf2aaa750 772533dd0e1c47cab78aea17284212fc X 7cf0700a556b479cbcf2690bf2aaa750--772533dd0e1c47cab78aea17284212fc 772533dd0e1c47cab78aea17284212fc--bd46a69cc721403aab541a79939f2863 772533dd0e1c47cab78aea17284212fc--b65adb48d7be458786cf3bfc300bfb2a 76568b59304249b1bac4cd7397492446 8684733eb7c545abb95c0a7045c43e73 X 4e1a389b6d5b4370ba1cbf0ae5a98a5b--8684733eb7c545abb95c0a7045c43e73 fd3facac0d2d433fadc45189f5a871d3 RX(theta₃) 8684733eb7c545abb95c0a7045c43e73--fd3facac0d2d433fadc45189f5a871d3 d86088c8b1834215bafb6c4735dc8519 RY(theta₇) fd3facac0d2d433fadc45189f5a871d3--d86088c8b1834215bafb6c4735dc8519 ebfc62c73405477db52f2774f73981e2 RX(theta₁₁) d86088c8b1834215bafb6c4735dc8519--ebfc62c73405477db52f2774f73981e2 2f32c77d5a1e4e23a42f91928215a8de X ebfc62c73405477db52f2774f73981e2--2f32c77d5a1e4e23a42f91928215a8de 2f32c77d5a1e4e23a42f91928215a8de--7d7abdf6de984f03b4bf1acf0b33c0c3 9a4d0e4cf97d4692b551f450753c9988 2f32c77d5a1e4e23a42f91928215a8de--9a4d0e4cf97d4692b551f450753c9988 e288ee201f18448db25ab8060ea5a399 RX(theta₁₅) 9a4d0e4cf97d4692b551f450753c9988--e288ee201f18448db25ab8060ea5a399 73deedfeadbe4bcbb83ac02ee4dc0941 RY(theta₁₉) e288ee201f18448db25ab8060ea5a399--73deedfeadbe4bcbb83ac02ee4dc0941 4b67a0b0a0e648f5954a9af0aec7a9fe RX(theta₂₃) 73deedfeadbe4bcbb83ac02ee4dc0941--4b67a0b0a0e648f5954a9af0aec7a9fe f3601e147ebc4a7e8c3ca690790e12ba X 4b67a0b0a0e648f5954a9af0aec7a9fe--f3601e147ebc4a7e8c3ca690790e12ba f3601e147ebc4a7e8c3ca690790e12ba--7cf0700a556b479cbcf2690bf2aaa750 8165123baaf640c5a772108446d6deb8 f3601e147ebc4a7e8c3ca690790e12ba--8165123baaf640c5a772108446d6deb8 8165123baaf640c5a772108446d6deb8--76568b59304249b1bac4cd7397492446
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, 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.4025-0.1833j, -0.2130-0.1846j,  0.0888+0.1441j,  0.2353+0.1470j,
         -0.0163+0.0063j, -0.5182-0.4070j,  0.0032-0.2105j,  0.3715-0.0498j],
        [ 0.5168-0.1029j,  0.1842-0.3470j,  0.3309-0.1683j,  0.0565-0.1246j,
          0.2506-0.3857j, -0.1022-0.3466j, -0.0437-0.0899j, -0.2311+0.0773j]])

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