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.91974994-0.39225289j 0.        +0.j         0.01293391-0.00551603j
 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_0f9fcb94d683434383a934ca4a9f7001 Circuit block cluster_8e51bb90dd5e4b89aa746888fb076fc4 Prep block def83a9958444041934e667d6e040870 0 aefd04442cb343b1beb9d14332faf0a4 def83a9958444041934e667d6e040870--aefd04442cb343b1beb9d14332faf0a4 0af18f9eea43452aa51f6d728a6653f5 1 336cb2bf82374784ac9b5bc61ac4602f RX(theta₀) aefd04442cb343b1beb9d14332faf0a4--336cb2bf82374784ac9b5bc61ac4602f ac04422a47044e7781d2a85f7980f26f RY(theta₄) 336cb2bf82374784ac9b5bc61ac4602f--ac04422a47044e7781d2a85f7980f26f f2f2d87051d648ff8ebc2e928343b4ad RX(theta₈) ac04422a47044e7781d2a85f7980f26f--f2f2d87051d648ff8ebc2e928343b4ad 05296305b30342b6a7e1042a9f315193 f2f2d87051d648ff8ebc2e928343b4ad--05296305b30342b6a7e1042a9f315193 2285ca5e91f9420cb6dd82f86a3900c5 05296305b30342b6a7e1042a9f315193--2285ca5e91f9420cb6dd82f86a3900c5 cd45c2f45e55490c82341829f29b29be RX(theta₁₂) 2285ca5e91f9420cb6dd82f86a3900c5--cd45c2f45e55490c82341829f29b29be a17e705596b4478cb30d3ad3b32df474 RY(theta₁₆) cd45c2f45e55490c82341829f29b29be--a17e705596b4478cb30d3ad3b32df474 3242aefd2d8644df8dc383e84c97a742 RX(theta₂₀) a17e705596b4478cb30d3ad3b32df474--3242aefd2d8644df8dc383e84c97a742 462b19fd00bb4795abaac184e33582cd 3242aefd2d8644df8dc383e84c97a742--462b19fd00bb4795abaac184e33582cd 66c5d4f05b6c47d9b7a0f7673d3c0599 462b19fd00bb4795abaac184e33582cd--66c5d4f05b6c47d9b7a0f7673d3c0599 673730a6b26c4ecfb618b787a511475e 66c5d4f05b6c47d9b7a0f7673d3c0599--673730a6b26c4ecfb618b787a511475e 9f540c8cb6be43b4ae68eff0bb58ef9d 10691efaa3f849f08e605c2b2fdc91aa 0af18f9eea43452aa51f6d728a6653f5--10691efaa3f849f08e605c2b2fdc91aa ff761c52709b45588c89c64a71d1a1cc 2 e13dc3d61e6e428795b0931e59278aa3 RX(theta₁) 10691efaa3f849f08e605c2b2fdc91aa--e13dc3d61e6e428795b0931e59278aa3 b7a37caa504a493fba487b157213cc75 RY(theta₅) e13dc3d61e6e428795b0931e59278aa3--b7a37caa504a493fba487b157213cc75 ca5fb5df364249138af514b3d6c9be47 RX(theta₉) b7a37caa504a493fba487b157213cc75--ca5fb5df364249138af514b3d6c9be47 c2d46148f8484e448125340be715e32e X ca5fb5df364249138af514b3d6c9be47--c2d46148f8484e448125340be715e32e c2d46148f8484e448125340be715e32e--05296305b30342b6a7e1042a9f315193 4d832d65f12844789a398485cbdefea7 c2d46148f8484e448125340be715e32e--4d832d65f12844789a398485cbdefea7 b14e48983e144ebea7c2bc14b27f0b7f RX(theta₁₃) 4d832d65f12844789a398485cbdefea7--b14e48983e144ebea7c2bc14b27f0b7f b4fda62301b440009f2bca586dd652fe RY(theta₁₇) b14e48983e144ebea7c2bc14b27f0b7f--b4fda62301b440009f2bca586dd652fe 8f1be86e94da45b28e5fc39db0f6d42d RX(theta₂₁) b4fda62301b440009f2bca586dd652fe--8f1be86e94da45b28e5fc39db0f6d42d c908c0b10aba4ecc96670992a56de155 X 8f1be86e94da45b28e5fc39db0f6d42d--c908c0b10aba4ecc96670992a56de155 c908c0b10aba4ecc96670992a56de155--462b19fd00bb4795abaac184e33582cd aed834dd3a384709afcebebc4da36481 c908c0b10aba4ecc96670992a56de155--aed834dd3a384709afcebebc4da36481 aed834dd3a384709afcebebc4da36481--9f540c8cb6be43b4ae68eff0bb58ef9d ab626f3cf9d745c9a24aa553317a0b39 1c2c2b959f294be08668096e37995044 ff761c52709b45588c89c64a71d1a1cc--1c2c2b959f294be08668096e37995044 abb5e327f36f416baecdf2c9adaf623a 3 18838a6084834f01963615b7103fe548 RX(theta₂) 1c2c2b959f294be08668096e37995044--18838a6084834f01963615b7103fe548 0473525638954690a77e7153cc53fe11 RY(theta₆) 18838a6084834f01963615b7103fe548--0473525638954690a77e7153cc53fe11 c8af770009ba4017a979a8cc4de215b8 RX(theta₁₀) 0473525638954690a77e7153cc53fe11--c8af770009ba4017a979a8cc4de215b8 00aeead939aa4dc6ba9f1319586957ae c8af770009ba4017a979a8cc4de215b8--00aeead939aa4dc6ba9f1319586957ae 5d0aec55d33b4369b6bbbff9d7766259 X 00aeead939aa4dc6ba9f1319586957ae--5d0aec55d33b4369b6bbbff9d7766259 5d0aec55d33b4369b6bbbff9d7766259--4d832d65f12844789a398485cbdefea7 08063425ae5249fb96d32f0cc501728b RX(theta₁₄) 5d0aec55d33b4369b6bbbff9d7766259--08063425ae5249fb96d32f0cc501728b f31317743cfe409ca215cae5def4f44d RY(theta₁₈) 08063425ae5249fb96d32f0cc501728b--f31317743cfe409ca215cae5def4f44d 8db8d4cba26f4872b4db9396591fd713 RX(theta₂₂) f31317743cfe409ca215cae5def4f44d--8db8d4cba26f4872b4db9396591fd713 25cbcacdede14669b89ec9d1f99cb58b 8db8d4cba26f4872b4db9396591fd713--25cbcacdede14669b89ec9d1f99cb58b 4f82c54156d14194be9c8c44b7bb7eda X 25cbcacdede14669b89ec9d1f99cb58b--4f82c54156d14194be9c8c44b7bb7eda 4f82c54156d14194be9c8c44b7bb7eda--aed834dd3a384709afcebebc4da36481 4f82c54156d14194be9c8c44b7bb7eda--ab626f3cf9d745c9a24aa553317a0b39 aeaaf9d65dd342cda25dcd0402fb2b57 5b219d3ecdee4e35b9e0a43f45198f9f X abb5e327f36f416baecdf2c9adaf623a--5b219d3ecdee4e35b9e0a43f45198f9f 777ad85679b24c0298db177072d214b3 RX(theta₃) 5b219d3ecdee4e35b9e0a43f45198f9f--777ad85679b24c0298db177072d214b3 3d80ee8251d043538df5c3708c385735 RY(theta₇) 777ad85679b24c0298db177072d214b3--3d80ee8251d043538df5c3708c385735 dae3d5931f134b78a365d2ce991e2db5 RX(theta₁₁) 3d80ee8251d043538df5c3708c385735--dae3d5931f134b78a365d2ce991e2db5 914b8086b3a44850825039d3eefb645a X dae3d5931f134b78a365d2ce991e2db5--914b8086b3a44850825039d3eefb645a 914b8086b3a44850825039d3eefb645a--00aeead939aa4dc6ba9f1319586957ae 3250cd298581413eb04a0e4d4845ff07 914b8086b3a44850825039d3eefb645a--3250cd298581413eb04a0e4d4845ff07 9d2812ea6756483495beaf12f3516e78 RX(theta₁₅) 3250cd298581413eb04a0e4d4845ff07--9d2812ea6756483495beaf12f3516e78 8df048252da344dfa23c34f689af4b0d RY(theta₁₉) 9d2812ea6756483495beaf12f3516e78--8df048252da344dfa23c34f689af4b0d 7a40583889044f2e8891534b2476af41 RX(theta₂₃) 8df048252da344dfa23c34f689af4b0d--7a40583889044f2e8891534b2476af41 d77a444144354e3e973455abc9c1dd7d X 7a40583889044f2e8891534b2476af41--d77a444144354e3e973455abc9c1dd7d d77a444144354e3e973455abc9c1dd7d--25cbcacdede14669b89ec9d1f99cb58b c899f7f2b1bc4f4787b1540f19922818 d77a444144354e3e973455abc9c1dd7d--c899f7f2b1bc4f4787b1540f19922818 c899f7f2b1bc4f4787b1540f19922818--aeaaf9d65dd342cda25dcd0402fb2b57
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, 0.+0.j, 1.+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.2942+0.3484j, -0.1539-0.0542j,  0.1777-0.0318j,  0.0127+0.6092j,
         -0.3757+0.0192j,  0.1158-0.3238j, -0.0533+0.0866j,  0.2110-0.2165j],
        [ 0.1984+0.3044j,  0.2583-0.1425j,  0.3276+0.0171j,  0.4575+0.0635j,
         -0.0397+0.1364j,  0.0219-0.2100j, -0.5043+0.1534j, -0.1100+0.3245j]])

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