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.60466101+0.58392443j 0.        +0.j         0.37628597-0.3896488j
 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_f54224870bd04f7f87572fcf5c078fa3 Circuit block cluster_9c1a63de8e9f47c0b1e73b710ed3f5ee Prep block d91c43f637b645af8e5d201857cb9444 0 84e34534809145479dc83a0c13e9c470 d91c43f637b645af8e5d201857cb9444--84e34534809145479dc83a0c13e9c470 e8ddd97055d84827a1a04531fb3fc6c4 1 e401cbe58a1642ac8b758ec224d315c8 RX(theta₀) 84e34534809145479dc83a0c13e9c470--e401cbe58a1642ac8b758ec224d315c8 97800fd73efc44b8a19c00dcdeb252bc RY(theta₄) e401cbe58a1642ac8b758ec224d315c8--97800fd73efc44b8a19c00dcdeb252bc 069dc93bbee542a9a83007726f9c9068 RX(theta₈) 97800fd73efc44b8a19c00dcdeb252bc--069dc93bbee542a9a83007726f9c9068 693edc30e3dd49b98644a97c1175eadb 069dc93bbee542a9a83007726f9c9068--693edc30e3dd49b98644a97c1175eadb 68989a7f628941e290c290659af58732 693edc30e3dd49b98644a97c1175eadb--68989a7f628941e290c290659af58732 c786c66871a242399ad52ff1c4b3a0ce RX(theta₁₂) 68989a7f628941e290c290659af58732--c786c66871a242399ad52ff1c4b3a0ce be52efadc13341a6bd9b5b133760ad42 RY(theta₁₆) c786c66871a242399ad52ff1c4b3a0ce--be52efadc13341a6bd9b5b133760ad42 a44494efaf554c9582fab7bf83ab6523 RX(theta₂₀) be52efadc13341a6bd9b5b133760ad42--a44494efaf554c9582fab7bf83ab6523 dbe4e4f26eb3442b96964bf934ce1009 a44494efaf554c9582fab7bf83ab6523--dbe4e4f26eb3442b96964bf934ce1009 f4fe0a8ad0c34e209be787a6f31aab9d dbe4e4f26eb3442b96964bf934ce1009--f4fe0a8ad0c34e209be787a6f31aab9d 2105a2dba9214f008a9390ae4030366e f4fe0a8ad0c34e209be787a6f31aab9d--2105a2dba9214f008a9390ae4030366e ef9ee374eeac41e293528da19a8fd39b f4888afd8b85453e925a4004767a98a1 e8ddd97055d84827a1a04531fb3fc6c4--f4888afd8b85453e925a4004767a98a1 922017bfc3a849fab1738893c8169596 2 7d4ecc189f93445799bb5670e6ea079d RX(theta₁) f4888afd8b85453e925a4004767a98a1--7d4ecc189f93445799bb5670e6ea079d d8193a4aa5d947b29b1230ffc991a387 RY(theta₅) 7d4ecc189f93445799bb5670e6ea079d--d8193a4aa5d947b29b1230ffc991a387 834c0299476241f9a99d40e181cfcc53 RX(theta₉) d8193a4aa5d947b29b1230ffc991a387--834c0299476241f9a99d40e181cfcc53 1e9521dfeb2c41a0b28023aa0d0a2bea X 834c0299476241f9a99d40e181cfcc53--1e9521dfeb2c41a0b28023aa0d0a2bea 1e9521dfeb2c41a0b28023aa0d0a2bea--693edc30e3dd49b98644a97c1175eadb 6f32e04c735747c5adf91c52e5d73f13 1e9521dfeb2c41a0b28023aa0d0a2bea--6f32e04c735747c5adf91c52e5d73f13 3f4c497a57084c81acf0cdffaee0c042 RX(theta₁₃) 6f32e04c735747c5adf91c52e5d73f13--3f4c497a57084c81acf0cdffaee0c042 fa73e4ff37224824a862928617c0db5b RY(theta₁₇) 3f4c497a57084c81acf0cdffaee0c042--fa73e4ff37224824a862928617c0db5b 7e6ec6eb3670488aa1d34a3ae61f7bec RX(theta₂₁) fa73e4ff37224824a862928617c0db5b--7e6ec6eb3670488aa1d34a3ae61f7bec 75ce104e7e434d4abc7d72cd1498c442 X 7e6ec6eb3670488aa1d34a3ae61f7bec--75ce104e7e434d4abc7d72cd1498c442 75ce104e7e434d4abc7d72cd1498c442--dbe4e4f26eb3442b96964bf934ce1009 29a9b1104a8f4265b5d613181b3c7206 75ce104e7e434d4abc7d72cd1498c442--29a9b1104a8f4265b5d613181b3c7206 29a9b1104a8f4265b5d613181b3c7206--ef9ee374eeac41e293528da19a8fd39b 29d1b959ed7b464986dcd0f68c7f83f2 4e525f2915124b73bb5b6a6778ba05b0 922017bfc3a849fab1738893c8169596--4e525f2915124b73bb5b6a6778ba05b0 3cf7b2c73cf54462acfbfd2521c5aa80 3 51ed73c2345c45c6a238b0e0b1ef2d3a RX(theta₂) 4e525f2915124b73bb5b6a6778ba05b0--51ed73c2345c45c6a238b0e0b1ef2d3a b34eb7cf3a4e484697829ae9b0877781 RY(theta₆) 51ed73c2345c45c6a238b0e0b1ef2d3a--b34eb7cf3a4e484697829ae9b0877781 5f65a54657834dafa3b7d1c2f96fb80d RX(theta₁₀) b34eb7cf3a4e484697829ae9b0877781--5f65a54657834dafa3b7d1c2f96fb80d 1dca8ecaecd243dc8c225d9266091169 5f65a54657834dafa3b7d1c2f96fb80d--1dca8ecaecd243dc8c225d9266091169 e310ab78af0f434384b6bbc15baa4d5b X 1dca8ecaecd243dc8c225d9266091169--e310ab78af0f434384b6bbc15baa4d5b e310ab78af0f434384b6bbc15baa4d5b--6f32e04c735747c5adf91c52e5d73f13 8fb8655b1b4d4555ae3b7e155151c684 RX(theta₁₄) e310ab78af0f434384b6bbc15baa4d5b--8fb8655b1b4d4555ae3b7e155151c684 af5ee18a03f641b99d12e777a00c2caf RY(theta₁₈) 8fb8655b1b4d4555ae3b7e155151c684--af5ee18a03f641b99d12e777a00c2caf 3982992647354d44b21b1dcf5cb73ea3 RX(theta₂₂) af5ee18a03f641b99d12e777a00c2caf--3982992647354d44b21b1dcf5cb73ea3 b91305b1b4494960afc6811432962f2c 3982992647354d44b21b1dcf5cb73ea3--b91305b1b4494960afc6811432962f2c e589b979ebef43f18e9957cbe659e2bc X b91305b1b4494960afc6811432962f2c--e589b979ebef43f18e9957cbe659e2bc e589b979ebef43f18e9957cbe659e2bc--29a9b1104a8f4265b5d613181b3c7206 e589b979ebef43f18e9957cbe659e2bc--29d1b959ed7b464986dcd0f68c7f83f2 58fcbc54229e427280c639cca1827244 33dbd89185e848f6972d4bfef948a3d5 X 3cf7b2c73cf54462acfbfd2521c5aa80--33dbd89185e848f6972d4bfef948a3d5 66f79e6a2c524ae6a8a92500566ff7d7 RX(theta₃) 33dbd89185e848f6972d4bfef948a3d5--66f79e6a2c524ae6a8a92500566ff7d7 8823849a2b07474ebac332d08d0114ce RY(theta₇) 66f79e6a2c524ae6a8a92500566ff7d7--8823849a2b07474ebac332d08d0114ce 2c28f7e81a46438d94f6a20db83dc1b0 RX(theta₁₁) 8823849a2b07474ebac332d08d0114ce--2c28f7e81a46438d94f6a20db83dc1b0 897b00eedaed4ee7b98cbb761cbee288 X 2c28f7e81a46438d94f6a20db83dc1b0--897b00eedaed4ee7b98cbb761cbee288 897b00eedaed4ee7b98cbb761cbee288--1dca8ecaecd243dc8c225d9266091169 3ba696b82c4740f9a20a5c8d650e2ec6 897b00eedaed4ee7b98cbb761cbee288--3ba696b82c4740f9a20a5c8d650e2ec6 12494a9cc02e49ff9f8e177fd998e30a RX(theta₁₅) 3ba696b82c4740f9a20a5c8d650e2ec6--12494a9cc02e49ff9f8e177fd998e30a efeb296cf7db42bfa09366b784063df7 RY(theta₁₉) 12494a9cc02e49ff9f8e177fd998e30a--efeb296cf7db42bfa09366b784063df7 893d9379973041c381e2d0021a6aefc4 RX(theta₂₃) efeb296cf7db42bfa09366b784063df7--893d9379973041c381e2d0021a6aefc4 0726e73ced9f432d85ecac2bed1bc20a X 893d9379973041c381e2d0021a6aefc4--0726e73ced9f432d85ecac2bed1bc20a 0726e73ced9f432d85ecac2bed1bc20a--b91305b1b4494960afc6811432962f2c 5156b2a222974b3b8465ae75f40f95ef 0726e73ced9f432d85ecac2bed1bc20a--5156b2a222974b3b8465ae75f40f95ef 5156b2a222974b3b8465ae75f40f95ef--58fcbc54229e427280c639cca1827244
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, 1.+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]])

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.2561-0.1032j,  0.0494+0.0587j,  0.3258+0.1880j,  0.2518-0.0606j,
         -0.3047-0.3365j, -0.0829+0.4560j,  0.2562+0.1226j, -0.1817+0.4180j],
        [ 0.3139+0.4935j, -0.2357+0.3002j,  0.4257+0.0696j,  0.0326+0.0448j,
          0.1226-0.1125j, -0.2873+0.1443j, -0.1797-0.3972j, -0.0041-0.0452j]])

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