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.58118498+0.j          0.        -0.81374446j  0.        -0.0038541j
 -0.0053963 +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_816cb842ffae43f3990255449ce8f50d Circuit block cluster_7a3d965a37454a81b27c93400f5b85a4 Prep block 89e28c26b1114782adcfc19b77609f4b 0 851751bb566f491b96bf33013526a77f 89e28c26b1114782adcfc19b77609f4b--851751bb566f491b96bf33013526a77f 03fba14459054177a2810b1a5f43cc7b 1 fa8a4c99bf2b415cb072f1888c92af7a RX(theta₀) 851751bb566f491b96bf33013526a77f--fa8a4c99bf2b415cb072f1888c92af7a 2c05a345e99946d19df69439138ee532 RY(theta₄) fa8a4c99bf2b415cb072f1888c92af7a--2c05a345e99946d19df69439138ee532 e64875f7912c4fb39fe3e6c431df4bd4 RX(theta₈) 2c05a345e99946d19df69439138ee532--e64875f7912c4fb39fe3e6c431df4bd4 94f1b868eb944469aeb7a3173dd1eaee e64875f7912c4fb39fe3e6c431df4bd4--94f1b868eb944469aeb7a3173dd1eaee ee9bfa48433a467a8b8039d1fde62265 94f1b868eb944469aeb7a3173dd1eaee--ee9bfa48433a467a8b8039d1fde62265 5a334550d3e5498fa101650e6c903a13 RX(theta₁₂) ee9bfa48433a467a8b8039d1fde62265--5a334550d3e5498fa101650e6c903a13 b58d9fc4186c48a1b14fb1e538ba8039 RY(theta₁₆) 5a334550d3e5498fa101650e6c903a13--b58d9fc4186c48a1b14fb1e538ba8039 712165eba6c542c68efcfaf4ddce7697 RX(theta₂₀) b58d9fc4186c48a1b14fb1e538ba8039--712165eba6c542c68efcfaf4ddce7697 978495cfbc954a188d85ecdaac9757d5 712165eba6c542c68efcfaf4ddce7697--978495cfbc954a188d85ecdaac9757d5 528c14ec6eb94d7ea8c9b5eceeeeddd8 978495cfbc954a188d85ecdaac9757d5--528c14ec6eb94d7ea8c9b5eceeeeddd8 44aae52292854a288b77e9e717c169d1 528c14ec6eb94d7ea8c9b5eceeeeddd8--44aae52292854a288b77e9e717c169d1 108aea92da344a09994143b51bf1539c f321dfbee0fb4b0f97f20de53b40139f 03fba14459054177a2810b1a5f43cc7b--f321dfbee0fb4b0f97f20de53b40139f 10a72475655f467faeafaf1c4787d24b 2 a4cb14169187477692dee8e857be17ae RX(theta₁) f321dfbee0fb4b0f97f20de53b40139f--a4cb14169187477692dee8e857be17ae b99261790c7b4bb99679934ba9a7424f RY(theta₅) a4cb14169187477692dee8e857be17ae--b99261790c7b4bb99679934ba9a7424f c6e0f96ad233487ca7e14fda944dff1c RX(theta₉) b99261790c7b4bb99679934ba9a7424f--c6e0f96ad233487ca7e14fda944dff1c ed863512fdc542d09e92d66593f7b936 X c6e0f96ad233487ca7e14fda944dff1c--ed863512fdc542d09e92d66593f7b936 ed863512fdc542d09e92d66593f7b936--94f1b868eb944469aeb7a3173dd1eaee 74b5066066c849f78e0645f06dc21825 ed863512fdc542d09e92d66593f7b936--74b5066066c849f78e0645f06dc21825 503feabc785d4f37b2144113d151bba4 RX(theta₁₃) 74b5066066c849f78e0645f06dc21825--503feabc785d4f37b2144113d151bba4 5cc71377c36e484ba1443d278dbdc3d7 RY(theta₁₇) 503feabc785d4f37b2144113d151bba4--5cc71377c36e484ba1443d278dbdc3d7 713193e16bf84264b2dfc9945028f45b RX(theta₂₁) 5cc71377c36e484ba1443d278dbdc3d7--713193e16bf84264b2dfc9945028f45b aaa3870e12594031a99f985813b5ec38 X 713193e16bf84264b2dfc9945028f45b--aaa3870e12594031a99f985813b5ec38 aaa3870e12594031a99f985813b5ec38--978495cfbc954a188d85ecdaac9757d5 3e674b7edeb041fbbd9408b52e1cca58 aaa3870e12594031a99f985813b5ec38--3e674b7edeb041fbbd9408b52e1cca58 3e674b7edeb041fbbd9408b52e1cca58--108aea92da344a09994143b51bf1539c 7dcc7674d3164adf907f3023a086608a 62ea3a6001074106809d90cba7a1e955 10a72475655f467faeafaf1c4787d24b--62ea3a6001074106809d90cba7a1e955 a029c968d9d44d87bde7680d1ce3a360 3 c1fd52ae4be247b28a47f9f6edc718cb RX(theta₂) 62ea3a6001074106809d90cba7a1e955--c1fd52ae4be247b28a47f9f6edc718cb 9b6f0f61867143ba87d1a15e4669cbff RY(theta₆) c1fd52ae4be247b28a47f9f6edc718cb--9b6f0f61867143ba87d1a15e4669cbff f482f7f2793f4f259ac75f6bdc765029 RX(theta₁₀) 9b6f0f61867143ba87d1a15e4669cbff--f482f7f2793f4f259ac75f6bdc765029 97bb660f3ca2428f973e627f61709d23 f482f7f2793f4f259ac75f6bdc765029--97bb660f3ca2428f973e627f61709d23 fb6da9d8e5ed4f688435db9cb57d5f4a X 97bb660f3ca2428f973e627f61709d23--fb6da9d8e5ed4f688435db9cb57d5f4a fb6da9d8e5ed4f688435db9cb57d5f4a--74b5066066c849f78e0645f06dc21825 762def0c97c646a2ad0d21bc6ce22421 RX(theta₁₄) fb6da9d8e5ed4f688435db9cb57d5f4a--762def0c97c646a2ad0d21bc6ce22421 697ff0354789444c807dcafd17cb31c6 RY(theta₁₈) 762def0c97c646a2ad0d21bc6ce22421--697ff0354789444c807dcafd17cb31c6 687ce6eef7b94c088d4af623600a44a1 RX(theta₂₂) 697ff0354789444c807dcafd17cb31c6--687ce6eef7b94c088d4af623600a44a1 87c9b19c883e42fc941e1672bc82eede 687ce6eef7b94c088d4af623600a44a1--87c9b19c883e42fc941e1672bc82eede 8fd2617e620d4a87bf3ea8643664cc0a X 87c9b19c883e42fc941e1672bc82eede--8fd2617e620d4a87bf3ea8643664cc0a 8fd2617e620d4a87bf3ea8643664cc0a--3e674b7edeb041fbbd9408b52e1cca58 8fd2617e620d4a87bf3ea8643664cc0a--7dcc7674d3164adf907f3023a086608a 33bff10b04c24da4b1facbb7a1f5d17f 08bec690ce7045249cf1c82284ab416d X a029c968d9d44d87bde7680d1ce3a360--08bec690ce7045249cf1c82284ab416d e7e6ab72dcbc4c7aa6cdae053792ad21 RX(theta₃) 08bec690ce7045249cf1c82284ab416d--e7e6ab72dcbc4c7aa6cdae053792ad21 7dc18f8b115b469cad1475979cf16ec1 RY(theta₇) e7e6ab72dcbc4c7aa6cdae053792ad21--7dc18f8b115b469cad1475979cf16ec1 99f7061bac334d56b48a544a896ed65b RX(theta₁₁) 7dc18f8b115b469cad1475979cf16ec1--99f7061bac334d56b48a544a896ed65b 9242f81729d847609ac17d4c5ed7e7bc X 99f7061bac334d56b48a544a896ed65b--9242f81729d847609ac17d4c5ed7e7bc 9242f81729d847609ac17d4c5ed7e7bc--97bb660f3ca2428f973e627f61709d23 655a34c061d64bddbcba2a3aa4b76ccf 9242f81729d847609ac17d4c5ed7e7bc--655a34c061d64bddbcba2a3aa4b76ccf 6c8c500277bc468c8fbbaae893ac4503 RX(theta₁₅) 655a34c061d64bddbcba2a3aa4b76ccf--6c8c500277bc468c8fbbaae893ac4503 226641a169884f598c8f2d268b8715e8 RY(theta₁₉) 6c8c500277bc468c8fbbaae893ac4503--226641a169884f598c8f2d268b8715e8 c846995a8cd54069944c0b623e34c64c RX(theta₂₃) 226641a169884f598c8f2d268b8715e8--c846995a8cd54069944c0b623e34c64c 6272c2e2458e4ea2a3d76c08deafe3c0 X c846995a8cd54069944c0b623e34c64c--6272c2e2458e4ea2a3d76c08deafe3c0 6272c2e2458e4ea2a3d76c08deafe3c0--87c9b19c883e42fc941e1672bc82eede d570b6db92fa4709a1adfff66fb3e422 6272c2e2458e4ea2a3d76c08deafe3c0--d570b6db92fa4709a1adfff66fb3e422 d570b6db92fa4709a1adfff66fb3e422--33bff10b04c24da4b1facbb7a1f5d17f
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, 0.+0.j, 0.+0.j, 1.+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.1938-0.0520j, -0.2004+0.3661j, -0.0483-0.0577j, -0.2657-0.3253j,
          0.4508+0.0664j,  0.2878+0.0577j, -0.2979+0.1222j, -0.0662+0.4491j],
        [ 0.2315-0.2451j,  0.2807+0.1053j, -0.3644+0.4587j, -0.0791+0.0530j,
         -0.0125-0.1685j,  0.2731-0.3878j, -0.3455-0.2506j, -0.0893-0.0241j]])

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