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_4c3909b1e1504173bb71d6296c619227 Circuit block cluster_95cbd247dba94b9ab47488d58bd87fd6 Prep block ed13de46a4594da4b1112d6e19ac2b4b 0 16acd06766ff41419a6171dd523f1608 ed13de46a4594da4b1112d6e19ac2b4b--16acd06766ff41419a6171dd523f1608 d5ef1c76b47a4bbba61e28528f3a4be8 1 08645b7f9a314ecdb14aaad1be8f7df7 RX(theta₀) 16acd06766ff41419a6171dd523f1608--08645b7f9a314ecdb14aaad1be8f7df7 a1c431cac98146028bf0a4d50645fda7 RY(theta₄) 08645b7f9a314ecdb14aaad1be8f7df7--a1c431cac98146028bf0a4d50645fda7 a0e894cda626487cafc774f9b048b77b RX(theta₈) a1c431cac98146028bf0a4d50645fda7--a0e894cda626487cafc774f9b048b77b 2accd7eedd3343809d856f00efcc2d9a a0e894cda626487cafc774f9b048b77b--2accd7eedd3343809d856f00efcc2d9a 6328046b112f4116bea83059ab43c5ee 2accd7eedd3343809d856f00efcc2d9a--6328046b112f4116bea83059ab43c5ee 0bad4fa858f14ad1b03601738ee75c86 RX(theta₁₂) 6328046b112f4116bea83059ab43c5ee--0bad4fa858f14ad1b03601738ee75c86 abacd7a534924728923183fb1a45593d RY(theta₁₆) 0bad4fa858f14ad1b03601738ee75c86--abacd7a534924728923183fb1a45593d f2bbafb0c9f2486f82d37aef7f49ac37 RX(theta₂₀) abacd7a534924728923183fb1a45593d--f2bbafb0c9f2486f82d37aef7f49ac37 c76b0fded87544c9ba5ca08d6350a410 f2bbafb0c9f2486f82d37aef7f49ac37--c76b0fded87544c9ba5ca08d6350a410 95b4d01ad3bd44328702ad9cacb428fe c76b0fded87544c9ba5ca08d6350a410--95b4d01ad3bd44328702ad9cacb428fe c03850a993ad474fb94727441ff2b472 95b4d01ad3bd44328702ad9cacb428fe--c03850a993ad474fb94727441ff2b472 ec0117186fe84959ba5310e0f091f2cf 5dc4243a2adb417d9d17a255afbe8bdf d5ef1c76b47a4bbba61e28528f3a4be8--5dc4243a2adb417d9d17a255afbe8bdf 8be03578480a4aaf90e21f47a380f327 2 37d0cf7b3f964c968558dd0a97905c67 RX(theta₁) 5dc4243a2adb417d9d17a255afbe8bdf--37d0cf7b3f964c968558dd0a97905c67 910c870fa5a34fdb86cee41eccc41f62 RY(theta₅) 37d0cf7b3f964c968558dd0a97905c67--910c870fa5a34fdb86cee41eccc41f62 c1f324421c5b44ec8c9e9146d8ea2c4c RX(theta₉) 910c870fa5a34fdb86cee41eccc41f62--c1f324421c5b44ec8c9e9146d8ea2c4c 39e73d4388f041e4859efd337816f471 X c1f324421c5b44ec8c9e9146d8ea2c4c--39e73d4388f041e4859efd337816f471 39e73d4388f041e4859efd337816f471--2accd7eedd3343809d856f00efcc2d9a b9af09421619432e8ed5839ca97ce6f9 39e73d4388f041e4859efd337816f471--b9af09421619432e8ed5839ca97ce6f9 1d15ae7a867b4506b4246eca0794bcaa RX(theta₁₃) b9af09421619432e8ed5839ca97ce6f9--1d15ae7a867b4506b4246eca0794bcaa 0dccd1f8e27543f29a4776fcf9272585 RY(theta₁₇) 1d15ae7a867b4506b4246eca0794bcaa--0dccd1f8e27543f29a4776fcf9272585 1c66ed73ed3e4f068a0335f027954e8d RX(theta₂₁) 0dccd1f8e27543f29a4776fcf9272585--1c66ed73ed3e4f068a0335f027954e8d a4987cd810694fb9b94d279f11595f25 X 1c66ed73ed3e4f068a0335f027954e8d--a4987cd810694fb9b94d279f11595f25 a4987cd810694fb9b94d279f11595f25--c76b0fded87544c9ba5ca08d6350a410 bd9f97105f094a85b35b7eb687f3a4f1 a4987cd810694fb9b94d279f11595f25--bd9f97105f094a85b35b7eb687f3a4f1 bd9f97105f094a85b35b7eb687f3a4f1--ec0117186fe84959ba5310e0f091f2cf ad5a07b13bdc47f6b3480ffbecf5060b 480363f734404f5f8c83af71f45b7453 8be03578480a4aaf90e21f47a380f327--480363f734404f5f8c83af71f45b7453 fabb6059e1fa4a05b88819a9c9481ded 3 985472a0d8904315a7e2a559b17a9f61 RX(theta₂) 480363f734404f5f8c83af71f45b7453--985472a0d8904315a7e2a559b17a9f61 b3d8abfa53b0470a8de4a221d5e9b4d5 RY(theta₆) 985472a0d8904315a7e2a559b17a9f61--b3d8abfa53b0470a8de4a221d5e9b4d5 b238097ff4894ebab11f804c6d1b9b4e RX(theta₁₀) b3d8abfa53b0470a8de4a221d5e9b4d5--b238097ff4894ebab11f804c6d1b9b4e a7c1d3f7d1df49708fd666e196bba846 b238097ff4894ebab11f804c6d1b9b4e--a7c1d3f7d1df49708fd666e196bba846 ec847b20c0884bc89f395f8aaf1eba50 X a7c1d3f7d1df49708fd666e196bba846--ec847b20c0884bc89f395f8aaf1eba50 ec847b20c0884bc89f395f8aaf1eba50--b9af09421619432e8ed5839ca97ce6f9 1ac6a1c46ef54fa8890f794cf35f66a4 RX(theta₁₄) ec847b20c0884bc89f395f8aaf1eba50--1ac6a1c46ef54fa8890f794cf35f66a4 30aaaf96afc44b2fa2c19f30fad2b834 RY(theta₁₈) 1ac6a1c46ef54fa8890f794cf35f66a4--30aaaf96afc44b2fa2c19f30fad2b834 a2c6f897904e4c8195bd74f8e01b51d0 RX(theta₂₂) 30aaaf96afc44b2fa2c19f30fad2b834--a2c6f897904e4c8195bd74f8e01b51d0 34984e3b140b4e168e1f7fbdfd57a68a a2c6f897904e4c8195bd74f8e01b51d0--34984e3b140b4e168e1f7fbdfd57a68a 096964289cd04852a6c15e5573948db9 X 34984e3b140b4e168e1f7fbdfd57a68a--096964289cd04852a6c15e5573948db9 096964289cd04852a6c15e5573948db9--bd9f97105f094a85b35b7eb687f3a4f1 096964289cd04852a6c15e5573948db9--ad5a07b13bdc47f6b3480ffbecf5060b eeb1383249fb40b2b527c8c8b903dcaa c363b67292054c1f8e3f7cfded6f8113 X fabb6059e1fa4a05b88819a9c9481ded--c363b67292054c1f8e3f7cfded6f8113 287a1cca6ce747e1a35709c8be8d28e8 RX(theta₃) c363b67292054c1f8e3f7cfded6f8113--287a1cca6ce747e1a35709c8be8d28e8 545dbc8166c44303a87594096c90fc85 RY(theta₇) 287a1cca6ce747e1a35709c8be8d28e8--545dbc8166c44303a87594096c90fc85 21f0771b93724743a715bb7078c35880 RX(theta₁₁) 545dbc8166c44303a87594096c90fc85--21f0771b93724743a715bb7078c35880 3fe023e389f14c99be072a8b3170baba X 21f0771b93724743a715bb7078c35880--3fe023e389f14c99be072a8b3170baba 3fe023e389f14c99be072a8b3170baba--a7c1d3f7d1df49708fd666e196bba846 090be7062f7444ebb11a484256361fa6 3fe023e389f14c99be072a8b3170baba--090be7062f7444ebb11a484256361fa6 79acecb37daf4af58d326f91c51e873f RX(theta₁₅) 090be7062f7444ebb11a484256361fa6--79acecb37daf4af58d326f91c51e873f 26c9a821ab0043e2a0a3f4c75b0698a0 RY(theta₁₉) 79acecb37daf4af58d326f91c51e873f--26c9a821ab0043e2a0a3f4c75b0698a0 3773eae14b024b0a811ddcfd2b6b9366 RX(theta₂₃) 26c9a821ab0043e2a0a3f4c75b0698a0--3773eae14b024b0a811ddcfd2b6b9366 468f03324b5342d6aaf5438050177d68 X 3773eae14b024b0a811ddcfd2b6b9366--468f03324b5342d6aaf5438050177d68 468f03324b5342d6aaf5438050177d68--34984e3b140b4e168e1f7fbdfd57a68a 9a76fd7754f0425096475d095d6bc029 468f03324b5342d6aaf5438050177d68--9a76fd7754f0425096475d095d6bc029 9a76fd7754f0425096475d095d6bc029--eeb1383249fb40b2b527c8c8b903dcaa
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]])