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" )
Ra n dom i n i t ial s tate ge nerate d wi t h ro tat io ns :
s tate = [ 0.95906007+0.28320273 j 0. + 0. j 0. + 0. j
0. + 0. j ]
Produc t s tate correspo n di n g t o bi tstr i n g ' 01 ' :
s tate = [ 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_88edb20c2d09423282a10c4dca66ab90
Circuit block
cluster_d5fc1a366de34314b93e58878e0f5877
Prep block
8365e1d6af6e4527a056b0754602b5b2
0
04a90a58c4f5435fa92f357a791abc7d
8365e1d6af6e4527a056b0754602b5b2--04a90a58c4f5435fa92f357a791abc7d
3e026bb4e83f4fbe9a4652a009780935
1
0a92954537db4449a17b923f90a157b8
RX(theta₀)
04a90a58c4f5435fa92f357a791abc7d--0a92954537db4449a17b923f90a157b8
eeee0eca30b14a89ba19353179e64037
RY(theta₄)
0a92954537db4449a17b923f90a157b8--eeee0eca30b14a89ba19353179e64037
3e3c19293d724a95b2772fba828e7b62
RX(theta₈)
eeee0eca30b14a89ba19353179e64037--3e3c19293d724a95b2772fba828e7b62
2460107fb237423d89af67c33890faf1
3e3c19293d724a95b2772fba828e7b62--2460107fb237423d89af67c33890faf1
573c61eb2317454e9ae25f5c688166a4
2460107fb237423d89af67c33890faf1--573c61eb2317454e9ae25f5c688166a4
282ab59406e74276a21b1d9043cdb635
RX(theta₁₂)
573c61eb2317454e9ae25f5c688166a4--282ab59406e74276a21b1d9043cdb635
9e1720acecd449c19400844ee1dae4bd
RY(theta₁₆)
282ab59406e74276a21b1d9043cdb635--9e1720acecd449c19400844ee1dae4bd
31f1862e71a046318f0f39d03f190078
RX(theta₂₀)
9e1720acecd449c19400844ee1dae4bd--31f1862e71a046318f0f39d03f190078
58981d93abce4cc7a078da61ef456d70
31f1862e71a046318f0f39d03f190078--58981d93abce4cc7a078da61ef456d70
4a62e9e915ee429eb981c867aa0ac4f3
58981d93abce4cc7a078da61ef456d70--4a62e9e915ee429eb981c867aa0ac4f3
d5814ca912ac47a4bf54b37e64320aa1
4a62e9e915ee429eb981c867aa0ac4f3--d5814ca912ac47a4bf54b37e64320aa1
20c6a5b3f6e548b29c39131ae7b8175f
8742ab7fe4d547a48aa0aa22eb44d8be
3e026bb4e83f4fbe9a4652a009780935--8742ab7fe4d547a48aa0aa22eb44d8be
452930b78a6e421c8c24d159d221ac60
2
4c6f0a7605c045d4b1d14f73bbf5bd22
RX(theta₁)
8742ab7fe4d547a48aa0aa22eb44d8be--4c6f0a7605c045d4b1d14f73bbf5bd22
523745abdfd640c0b3a3570746811dfe
RY(theta₅)
4c6f0a7605c045d4b1d14f73bbf5bd22--523745abdfd640c0b3a3570746811dfe
0dbf0aa3527f4c3a8997e123b92d4de0
RX(theta₉)
523745abdfd640c0b3a3570746811dfe--0dbf0aa3527f4c3a8997e123b92d4de0
c792e988497a41ebb60ca19375177b67
X
0dbf0aa3527f4c3a8997e123b92d4de0--c792e988497a41ebb60ca19375177b67
c792e988497a41ebb60ca19375177b67--2460107fb237423d89af67c33890faf1
092c53943c4d43ecb4ffcf3b58465488
c792e988497a41ebb60ca19375177b67--092c53943c4d43ecb4ffcf3b58465488
6f4aa08f2f82428296ea8fd7a7fc6501
RX(theta₁₃)
092c53943c4d43ecb4ffcf3b58465488--6f4aa08f2f82428296ea8fd7a7fc6501
8292c3a5b0fd424aabf353f2010835ec
RY(theta₁₇)
6f4aa08f2f82428296ea8fd7a7fc6501--8292c3a5b0fd424aabf353f2010835ec
66a100647ceb4e34af1536c1d8a2106e
RX(theta₂₁)
8292c3a5b0fd424aabf353f2010835ec--66a100647ceb4e34af1536c1d8a2106e
815b2b2f52f24062bcb8bfddc302fcca
X
66a100647ceb4e34af1536c1d8a2106e--815b2b2f52f24062bcb8bfddc302fcca
815b2b2f52f24062bcb8bfddc302fcca--58981d93abce4cc7a078da61ef456d70
6851e8ac7bdf4af88d795b53cbaf25cd
815b2b2f52f24062bcb8bfddc302fcca--6851e8ac7bdf4af88d795b53cbaf25cd
6851e8ac7bdf4af88d795b53cbaf25cd--20c6a5b3f6e548b29c39131ae7b8175f
ecd823085b654e87810f909f4ed18dc5
5456698631b44cd99f8a7ae987d50293
452930b78a6e421c8c24d159d221ac60--5456698631b44cd99f8a7ae987d50293
56019214a71045349087220adec6b25c
3
b08e1ec2fa4d4a2bbaf59b39b95ab0de
RX(theta₂)
5456698631b44cd99f8a7ae987d50293--b08e1ec2fa4d4a2bbaf59b39b95ab0de
54889f73bc244d30800c9fb5cf702eda
RY(theta₆)
b08e1ec2fa4d4a2bbaf59b39b95ab0de--54889f73bc244d30800c9fb5cf702eda
dca265a130ed4ac79f93e26f367f4dc9
RX(theta₁₀)
54889f73bc244d30800c9fb5cf702eda--dca265a130ed4ac79f93e26f367f4dc9
f59e2b501c7d4fba9c72e43db1e96753
dca265a130ed4ac79f93e26f367f4dc9--f59e2b501c7d4fba9c72e43db1e96753
9934396648784ff784e7e6d687dbd0d0
X
f59e2b501c7d4fba9c72e43db1e96753--9934396648784ff784e7e6d687dbd0d0
9934396648784ff784e7e6d687dbd0d0--092c53943c4d43ecb4ffcf3b58465488
dcf30b64f58e43a8b463fd1719cf7b20
RX(theta₁₄)
9934396648784ff784e7e6d687dbd0d0--dcf30b64f58e43a8b463fd1719cf7b20
480d688e7e10456ab957fcd497672d18
RY(theta₁₈)
dcf30b64f58e43a8b463fd1719cf7b20--480d688e7e10456ab957fcd497672d18
b008f68ea24c4d238642464bd6176321
RX(theta₂₂)
480d688e7e10456ab957fcd497672d18--b008f68ea24c4d238642464bd6176321
37c6264aba9942fd8ce9c954b8bb3437
b008f68ea24c4d238642464bd6176321--37c6264aba9942fd8ce9c954b8bb3437
12036dbeb778449cbb6a53efdd045e40
X
37c6264aba9942fd8ce9c954b8bb3437--12036dbeb778449cbb6a53efdd045e40
12036dbeb778449cbb6a53efdd045e40--6851e8ac7bdf4af88d795b53cbaf25cd
12036dbeb778449cbb6a53efdd045e40--ecd823085b654e87810f909f4ed18dc5
7cd58e8b790d4e44ba2764effe6fefea
9fa97f9a9adc42ee8d25097139a46c07
X
56019214a71045349087220adec6b25c--9fa97f9a9adc42ee8d25097139a46c07
8ca221f817574054ae504a62994076a4
RX(theta₃)
9fa97f9a9adc42ee8d25097139a46c07--8ca221f817574054ae504a62994076a4
117a6a98d20343d6855aca00b6191c55
RY(theta₇)
8ca221f817574054ae504a62994076a4--117a6a98d20343d6855aca00b6191c55
a9bf44ae986f4eb8a403c9aa5b2411a0
RX(theta₁₁)
117a6a98d20343d6855aca00b6191c55--a9bf44ae986f4eb8a403c9aa5b2411a0
4bb42067adbd4598a29dc0fa39f36d2e
X
a9bf44ae986f4eb8a403c9aa5b2411a0--4bb42067adbd4598a29dc0fa39f36d2e
4bb42067adbd4598a29dc0fa39f36d2e--f59e2b501c7d4fba9c72e43db1e96753
489385547e704d2f853fc778c10b1cd4
4bb42067adbd4598a29dc0fa39f36d2e--489385547e704d2f853fc778c10b1cd4
ea0f261c12db46bc88a973ffddc00fa6
RX(theta₁₅)
489385547e704d2f853fc778c10b1cd4--ea0f261c12db46bc88a973ffddc00fa6
a87e3b9fa10e4b09b385ad1780eafd44
RY(theta₁₉)
ea0f261c12db46bc88a973ffddc00fa6--a87e3b9fa10e4b09b385ad1780eafd44
ea5a70867ae54cadbb3654786dc88829
RX(theta₂₃)
a87e3b9fa10e4b09b385ad1780eafd44--ea5a70867ae54cadbb3654786dc88829
14a06f8f578f4acca4e0349f7676d9d5
X
ea5a70867ae54cadbb3654786dc88829--14a06f8f578f4acca4e0349f7676d9d5
14a06f8f578f4acca4e0349f7676d9d5--37c6264aba9942fd8ce9c954b8bb3437
33e9eacafd734cbb87198c7294a682cc
14a06f8f578f4acca4e0349f7676d9d5--33e9eacafd734cbb87198c7294a682cc
33e9eacafd734cbb87198c7294a682cc--7cd58e8b790d4e44ba2764effe6fefea
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 )
U n i f orm s tate =
tens or( [[ 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 s tate =
tens or( [[ 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 ]] )
O ne s tate =
tens or( [[ 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 )
Produc t s tate =
tens or( [[ 0.+0. j , 0.+0. j , 0.+0. j , 0.+0. j , 1.+0. j , 0.+0. j , 0.+0. j , 0.+0. j ]] )
Ra n dom s tate =
tens or( [[ 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 , 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 s tate =
tens or( [[ 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 )
Ra n dom s tate fr om Haar =
tens or( [[ -0.1979+0.1218 j , 0.3503-0.3097 j , -0.2027+0.2565 j , 0.2727-0.3882 j ,
0.3138+0.4586 j , 0.2025-0.1360 j , 0.1061+0.0889 j , 0.0225-0.0858 j ],
[ 0.5372+0.3381 j , 0.3074-0.1143 j , -0.2248+0.0703 j , -0.0898-0.2938 j ,
-0.0896-0.1091 j , -0.1593-0.4118 j , 0.2188+0.1255 j , -0.2026+0.1417 j ]] )
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 )
Fi nal s tate = tens or( [[ 0.+0. j , 0.+0. j , 0.+0. j , 1.+0. j ]] )
Density matrices conversion
It is also possible to obtain density matrices from statevectors. They can be passed as inputs to quantum programs performing density matrix based operations such as noisy simulations, when the backend allows such as PyQTorch.
from qadence import product_state , density_mat
init_state = product_state ( "10" )
init_density_matrix = density_mat ( init_state )
final_density_matrix = run ( CNOT ( 0 , 1 ), state = init_density_matrix )
I n i t ial = De ns i t yMa tr ix( [[[ 0.+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 , 0.+0. j , 1.+0. j , 0.+0. j ],
[ 0.+0. j , 0.+0. j , 0.+0. j , 0.+0. j ]]] )
Fi nal = De ns i t yMa tr ix( [[[ 0.-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 , 0.-0. j , 0.-0. j , 0.-0. j ],
[ 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 )
Kro n Block( 0 , 1 , 2 )
├── H( 0 )
├── H( 1 )
└── H( 2 )
Kro n Block( 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 )
Kro n Block( 0 , 1 , 2 )
├── X( 0 )
├── I( 1 )
└── I( 2 )
Kro n Block( 0 , 1 , 2 )
├── I( 0 )
├── I( 1 )
└── X( 2 )
And GHZ states:
from qadence import ghz_block
ghz_block = ghz_block ( n_qubits )
Chai n Block( 0 , 1 , 2 )
├── H( 0 )
└── Chai n Block( 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 )
Ca te gorical(probs : t orch.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 ))
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 ))
tens or( [[ 0.5000+0. j , 0.5000+0. j , 0.5000+0. j , 0.5000+0. j ]] )