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.48073329-0.34951263 j 0. + 0. j -0.47290848-0.65045676 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_6eaaf7246d2548ec876bab0c650f21d6
Circuit block
cluster_116d789419584da68b5830c2e433abf9
Prep block
8b8cb6f58a3f41e18c5b7ef68c3b3cd0
0
a5057b35f44f403ca40d7230dfd77e4c
8b8cb6f58a3f41e18c5b7ef68c3b3cd0--a5057b35f44f403ca40d7230dfd77e4c
0cb10c366021460198ce3ca413cc3c4f
1
8a95f7ca7e204fc1a93e1c5e5192e78a
RX(theta₀)
a5057b35f44f403ca40d7230dfd77e4c--8a95f7ca7e204fc1a93e1c5e5192e78a
ee8eee636b9b401187c59465cbd2936e
RY(theta₄)
8a95f7ca7e204fc1a93e1c5e5192e78a--ee8eee636b9b401187c59465cbd2936e
4c030454b2e84a23be8cc0a336a4a6da
RX(theta₈)
ee8eee636b9b401187c59465cbd2936e--4c030454b2e84a23be8cc0a336a4a6da
f856f13fb8ba4966a83538d786712015
4c030454b2e84a23be8cc0a336a4a6da--f856f13fb8ba4966a83538d786712015
e878da0f695a44cb8edf20480f3b715e
f856f13fb8ba4966a83538d786712015--e878da0f695a44cb8edf20480f3b715e
9f684aa010344638b0f02a049589ce27
RX(theta₁₂)
e878da0f695a44cb8edf20480f3b715e--9f684aa010344638b0f02a049589ce27
ea85df960a1d4290a221c38600f9c803
RY(theta₁₆)
9f684aa010344638b0f02a049589ce27--ea85df960a1d4290a221c38600f9c803
c6068e2cee574e6d99e977c189ee2116
RX(theta₂₀)
ea85df960a1d4290a221c38600f9c803--c6068e2cee574e6d99e977c189ee2116
b08a5a3f5b0742e0b225871a537031db
c6068e2cee574e6d99e977c189ee2116--b08a5a3f5b0742e0b225871a537031db
4a7025bc1e4446679132aa7e227a2c9e
b08a5a3f5b0742e0b225871a537031db--4a7025bc1e4446679132aa7e227a2c9e
3d1c15f96bc340698c95517f2d9ee07a
4a7025bc1e4446679132aa7e227a2c9e--3d1c15f96bc340698c95517f2d9ee07a
12a4cb9a522b4f76a32813bc43e4eb38
69b0f903705e4e6ea8424339a1dc532e
0cb10c366021460198ce3ca413cc3c4f--69b0f903705e4e6ea8424339a1dc532e
970c6a5397dd4cf8950c626711017f6f
2
6f70ac6fc7814ce9acb3083be8859479
RX(theta₁)
69b0f903705e4e6ea8424339a1dc532e--6f70ac6fc7814ce9acb3083be8859479
c94cdf64113a4410a19086573c75927d
RY(theta₅)
6f70ac6fc7814ce9acb3083be8859479--c94cdf64113a4410a19086573c75927d
57879d78709241a7a71e64a6fbe225e7
RX(theta₉)
c94cdf64113a4410a19086573c75927d--57879d78709241a7a71e64a6fbe225e7
3d9b0fb431bd4323a07e795c5a60b980
X
57879d78709241a7a71e64a6fbe225e7--3d9b0fb431bd4323a07e795c5a60b980
3d9b0fb431bd4323a07e795c5a60b980--f856f13fb8ba4966a83538d786712015
48072dee973946e8b450c7cde99ca38f
3d9b0fb431bd4323a07e795c5a60b980--48072dee973946e8b450c7cde99ca38f
61beccdda9224847a50ed25ffbb4547a
RX(theta₁₃)
48072dee973946e8b450c7cde99ca38f--61beccdda9224847a50ed25ffbb4547a
49d5484f2ee54f8d9169b025f753c00b
RY(theta₁₇)
61beccdda9224847a50ed25ffbb4547a--49d5484f2ee54f8d9169b025f753c00b
6460dfbf639c44dabe56509b6210dea2
RX(theta₂₁)
49d5484f2ee54f8d9169b025f753c00b--6460dfbf639c44dabe56509b6210dea2
7fc65a3b80ef45d5a1a0587b8f7cfaa9
X
6460dfbf639c44dabe56509b6210dea2--7fc65a3b80ef45d5a1a0587b8f7cfaa9
7fc65a3b80ef45d5a1a0587b8f7cfaa9--b08a5a3f5b0742e0b225871a537031db
633f36b23af4429ea0e1506e879a6c50
7fc65a3b80ef45d5a1a0587b8f7cfaa9--633f36b23af4429ea0e1506e879a6c50
633f36b23af4429ea0e1506e879a6c50--12a4cb9a522b4f76a32813bc43e4eb38
930f5edc75594a378e6814811d99eb79
50ca25ee1fcf48bc81274f839d7e5a41
970c6a5397dd4cf8950c626711017f6f--50ca25ee1fcf48bc81274f839d7e5a41
2e027f33e2b04ff8bdd8869e75ab9350
3
7b974d44e51f470a8456cc2548dd325b
RX(theta₂)
50ca25ee1fcf48bc81274f839d7e5a41--7b974d44e51f470a8456cc2548dd325b
f6ab36cbfb744767b71e20359b2c6bc3
RY(theta₆)
7b974d44e51f470a8456cc2548dd325b--f6ab36cbfb744767b71e20359b2c6bc3
f4bef8f5a550438e9bc7f6485c983cf0
RX(theta₁₀)
f6ab36cbfb744767b71e20359b2c6bc3--f4bef8f5a550438e9bc7f6485c983cf0
cda7eb1b32dd4416b9803f5351154b48
f4bef8f5a550438e9bc7f6485c983cf0--cda7eb1b32dd4416b9803f5351154b48
bec2b372745d494f8094c2164fc7c3a8
X
cda7eb1b32dd4416b9803f5351154b48--bec2b372745d494f8094c2164fc7c3a8
bec2b372745d494f8094c2164fc7c3a8--48072dee973946e8b450c7cde99ca38f
13108b0600f14edda75e4abb147358ac
RX(theta₁₄)
bec2b372745d494f8094c2164fc7c3a8--13108b0600f14edda75e4abb147358ac
7ae3afb060e04222a00c41d546f35924
RY(theta₁₈)
13108b0600f14edda75e4abb147358ac--7ae3afb060e04222a00c41d546f35924
c388a1ba3551483186d93d72a6d90409
RX(theta₂₂)
7ae3afb060e04222a00c41d546f35924--c388a1ba3551483186d93d72a6d90409
ce7e7c40baf34e1aa03314dd5648aa2c
c388a1ba3551483186d93d72a6d90409--ce7e7c40baf34e1aa03314dd5648aa2c
59fe0223808b41bcaa540f5251d80040
X
ce7e7c40baf34e1aa03314dd5648aa2c--59fe0223808b41bcaa540f5251d80040
59fe0223808b41bcaa540f5251d80040--633f36b23af4429ea0e1506e879a6c50
59fe0223808b41bcaa540f5251d80040--930f5edc75594a378e6814811d99eb79
bbf9015c779d4b4a92f5e7ea9eb4c568
0ba1e0859f35459cb90d04deb6ad788c
X
2e027f33e2b04ff8bdd8869e75ab9350--0ba1e0859f35459cb90d04deb6ad788c
ca9ee3a599cb4dd1a28a183310f86666
RX(theta₃)
0ba1e0859f35459cb90d04deb6ad788c--ca9ee3a599cb4dd1a28a183310f86666
5695359803b144ca817c952e6c566b61
RY(theta₇)
ca9ee3a599cb4dd1a28a183310f86666--5695359803b144ca817c952e6c566b61
a6217ac7790f4e4e97ad3d7cd689d02c
RX(theta₁₁)
5695359803b144ca817c952e6c566b61--a6217ac7790f4e4e97ad3d7cd689d02c
5dbeb20b3cc44971916b149b51953802
X
a6217ac7790f4e4e97ad3d7cd689d02c--5dbeb20b3cc44971916b149b51953802
5dbeb20b3cc44971916b149b51953802--cda7eb1b32dd4416b9803f5351154b48
e95cb8bc14324fcfa51fc1aa689405bc
5dbeb20b3cc44971916b149b51953802--e95cb8bc14324fcfa51fc1aa689405bc
53226b3fc4384a9f893d05f9974e96f0
RX(theta₁₅)
e95cb8bc14324fcfa51fc1aa689405bc--53226b3fc4384a9f893d05f9974e96f0
6fed055e94014b94b764226042de8530
RY(theta₁₉)
53226b3fc4384a9f893d05f9974e96f0--6fed055e94014b94b764226042de8530
fb6c70f706b649348fbc2b449ffe68a7
RX(theta₂₃)
6fed055e94014b94b764226042de8530--fb6c70f706b649348fbc2b449ffe68a7
28efb9f4b86d4fdda7f9ee4cc9c48ef7
X
fb6c70f706b649348fbc2b449ffe68a7--28efb9f4b86d4fdda7f9ee4cc9c48ef7
28efb9f4b86d4fdda7f9ee4cc9c48ef7--ce7e7c40baf34e1aa03314dd5648aa2c
c138f5308e99485e843f79b56f3da506
28efb9f4b86d4fdda7f9ee4cc9c48ef7--c138f5308e99485e843f79b56f3da506
c138f5308e99485e843f79b56f3da506--bbf9015c779d4b4a92f5e7ea9eb4c568
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( [[ 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 , 0.+0. j , 0.+0. j , 1.+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 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.3557+0.3074 j , 0.3065-0.3146 j , 0.2787-0.3765 j , -0.1341-0.2752 j ,
0.0773+0.1036 j , 0.2299-0.2545 j , 0.3054+0.0909 j , -0.0257-0.1907 j ],
[ -0.1873+0.2601 j , -0.2972-0.3651 j , 0.0140-0.1523 j , 0.0253-0.2675 j ,
-0.1018+0.2061 j , 0.1370-0.2704 j , -0.5043+0.4027 j , 0.0351-0.1327 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 ]] )