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.38529803+0. j 0. + 0.55576108 j 0. -0.41971478 j
0.60540445+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_ee379cb5733d4200ae1e60c4b20dc17c
Circuit block
cluster_8b733295bd564580ab16fe6972f5e045
Prep block
2ec9b767a42f42b4a51a31967ed75205
0
7b67e8f4ff3c4d4499c5383ecc9c3423
2ec9b767a42f42b4a51a31967ed75205--7b67e8f4ff3c4d4499c5383ecc9c3423
594b117fe6074d19ab12bb5375632189
1
718459294d2a4956b48da8eebb00c24e
RX(theta₀)
7b67e8f4ff3c4d4499c5383ecc9c3423--718459294d2a4956b48da8eebb00c24e
328d31a2e5e344c68a1640f2cb749d2f
RY(theta₄)
718459294d2a4956b48da8eebb00c24e--328d31a2e5e344c68a1640f2cb749d2f
90cc7d6f278f48af951bf8c5154a20e0
RX(theta₈)
328d31a2e5e344c68a1640f2cb749d2f--90cc7d6f278f48af951bf8c5154a20e0
bf5c98ab274042f7986732e0e5f9617c
90cc7d6f278f48af951bf8c5154a20e0--bf5c98ab274042f7986732e0e5f9617c
66169f65a39a4cfb878d1631ef5f7b20
bf5c98ab274042f7986732e0e5f9617c--66169f65a39a4cfb878d1631ef5f7b20
8f16f816d8204b348cac61c46d364def
RX(theta₁₂)
66169f65a39a4cfb878d1631ef5f7b20--8f16f816d8204b348cac61c46d364def
9ce536e9f96a45248395b55779c2de38
RY(theta₁₆)
8f16f816d8204b348cac61c46d364def--9ce536e9f96a45248395b55779c2de38
c968fc1e51004703909dd2d79ba5218b
RX(theta₂₀)
9ce536e9f96a45248395b55779c2de38--c968fc1e51004703909dd2d79ba5218b
db4e640eebcd4396a89f68f184404400
c968fc1e51004703909dd2d79ba5218b--db4e640eebcd4396a89f68f184404400
87197e4f52e7427ebf5369a8837dd2e7
db4e640eebcd4396a89f68f184404400--87197e4f52e7427ebf5369a8837dd2e7
65ad8852f02e46bbbc54977b05ffc08d
87197e4f52e7427ebf5369a8837dd2e7--65ad8852f02e46bbbc54977b05ffc08d
df95f63070cb4bc18d268a7e7ef0770c
1931cd29ce3b47758e9866fb50f6424f
594b117fe6074d19ab12bb5375632189--1931cd29ce3b47758e9866fb50f6424f
296e7583e1db4c5589b8277cd5716f02
2
1a97db961c6f41f29347eed8526c567e
RX(theta₁)
1931cd29ce3b47758e9866fb50f6424f--1a97db961c6f41f29347eed8526c567e
fc5e23d44db74da2a53fd7b5974c832f
RY(theta₅)
1a97db961c6f41f29347eed8526c567e--fc5e23d44db74da2a53fd7b5974c832f
6bf6c8bc81ce410bb085987eb554f38c
RX(theta₉)
fc5e23d44db74da2a53fd7b5974c832f--6bf6c8bc81ce410bb085987eb554f38c
5e24d3ee0ffc47e6a45c214cbfa6eb94
X
6bf6c8bc81ce410bb085987eb554f38c--5e24d3ee0ffc47e6a45c214cbfa6eb94
5e24d3ee0ffc47e6a45c214cbfa6eb94--bf5c98ab274042f7986732e0e5f9617c
7534d3732c1440079a9d60e499e5b830
5e24d3ee0ffc47e6a45c214cbfa6eb94--7534d3732c1440079a9d60e499e5b830
0853dee4bf584a0cb4c2b07ba5b24f88
RX(theta₁₃)
7534d3732c1440079a9d60e499e5b830--0853dee4bf584a0cb4c2b07ba5b24f88
aae1d121579342469865202e4cd7a1c2
RY(theta₁₇)
0853dee4bf584a0cb4c2b07ba5b24f88--aae1d121579342469865202e4cd7a1c2
b3f955a854064f6882eb8b14bfc1148d
RX(theta₂₁)
aae1d121579342469865202e4cd7a1c2--b3f955a854064f6882eb8b14bfc1148d
976aba2a74b34284ac6e7b3ccb1cb5fc
X
b3f955a854064f6882eb8b14bfc1148d--976aba2a74b34284ac6e7b3ccb1cb5fc
976aba2a74b34284ac6e7b3ccb1cb5fc--db4e640eebcd4396a89f68f184404400
fd7730faa9194d98a353cf1ffccb8c31
976aba2a74b34284ac6e7b3ccb1cb5fc--fd7730faa9194d98a353cf1ffccb8c31
fd7730faa9194d98a353cf1ffccb8c31--df95f63070cb4bc18d268a7e7ef0770c
f316814019674fcc93676b209bdaa8bc
52ee22c4133e40728fbf9c563d3d0d95
296e7583e1db4c5589b8277cd5716f02--52ee22c4133e40728fbf9c563d3d0d95
49e3a7b0cb114820a57c5985dd7e112d
3
72c86e4518254623b81ae24563d228cc
RX(theta₂)
52ee22c4133e40728fbf9c563d3d0d95--72c86e4518254623b81ae24563d228cc
983e74d8f3654f1ebb4f046f2d061ff4
RY(theta₆)
72c86e4518254623b81ae24563d228cc--983e74d8f3654f1ebb4f046f2d061ff4
63ac253c50934ee291dba47078da84f6
RX(theta₁₀)
983e74d8f3654f1ebb4f046f2d061ff4--63ac253c50934ee291dba47078da84f6
bac982c1bd7f42458cc15d2ea3dc4dd5
63ac253c50934ee291dba47078da84f6--bac982c1bd7f42458cc15d2ea3dc4dd5
b19c8a5ae1724f03976145b0c4cfac00
X
bac982c1bd7f42458cc15d2ea3dc4dd5--b19c8a5ae1724f03976145b0c4cfac00
b19c8a5ae1724f03976145b0c4cfac00--7534d3732c1440079a9d60e499e5b830
ca29d780506c45f082e8efd32ac189c1
RX(theta₁₄)
b19c8a5ae1724f03976145b0c4cfac00--ca29d780506c45f082e8efd32ac189c1
722b89887586420e8fe38df72a87ded6
RY(theta₁₈)
ca29d780506c45f082e8efd32ac189c1--722b89887586420e8fe38df72a87ded6
044ba763bccf457f9fd7804cd68e80e3
RX(theta₂₂)
722b89887586420e8fe38df72a87ded6--044ba763bccf457f9fd7804cd68e80e3
7c4066648a2443c7ae9ba7091c7b7642
044ba763bccf457f9fd7804cd68e80e3--7c4066648a2443c7ae9ba7091c7b7642
1eefff33bcde451d8af53608157d4571
X
7c4066648a2443c7ae9ba7091c7b7642--1eefff33bcde451d8af53608157d4571
1eefff33bcde451d8af53608157d4571--fd7730faa9194d98a353cf1ffccb8c31
1eefff33bcde451d8af53608157d4571--f316814019674fcc93676b209bdaa8bc
d78ce26eb9464ff9a1f6a24a3dc7704a
3c3446e57dd049e3bd193dc90738942d
X
49e3a7b0cb114820a57c5985dd7e112d--3c3446e57dd049e3bd193dc90738942d
cea4aceacbe349228afa624de4ad1337
RX(theta₃)
3c3446e57dd049e3bd193dc90738942d--cea4aceacbe349228afa624de4ad1337
640bf636f8624b649ee39da384d1b665
RY(theta₇)
cea4aceacbe349228afa624de4ad1337--640bf636f8624b649ee39da384d1b665
266dab4134124cf7bf8b4eff1cec3ed4
RX(theta₁₁)
640bf636f8624b649ee39da384d1b665--266dab4134124cf7bf8b4eff1cec3ed4
f021d5d76d4c4f60985ccfd831bf095d
X
266dab4134124cf7bf8b4eff1cec3ed4--f021d5d76d4c4f60985ccfd831bf095d
f021d5d76d4c4f60985ccfd831bf095d--bac982c1bd7f42458cc15d2ea3dc4dd5
17af3ab9e2b94db88ed32b9ed1c0a1ba
f021d5d76d4c4f60985ccfd831bf095d--17af3ab9e2b94db88ed32b9ed1c0a1ba
2b9a3e6787314c978fc53f71cdb819b6
RX(theta₁₅)
17af3ab9e2b94db88ed32b9ed1c0a1ba--2b9a3e6787314c978fc53f71cdb819b6
39a05013a8ba468bb64d4e8afe67c509
RY(theta₁₉)
2b9a3e6787314c978fc53f71cdb819b6--39a05013a8ba468bb64d4e8afe67c509
d66e0b09ebdf4cb9980e34e12fc88dde
RX(theta₂₃)
39a05013a8ba468bb64d4e8afe67c509--d66e0b09ebdf4cb9980e34e12fc88dde
74a9d5a236a84b838baeee0d5f25d02c
X
d66e0b09ebdf4cb9980e34e12fc88dde--74a9d5a236a84b838baeee0d5f25d02c
74a9d5a236a84b838baeee0d5f25d02c--7c4066648a2443c7ae9ba7091c7b7642
6406ec8a65a24fd785564006716b234d
74a9d5a236a84b838baeee0d5f25d02c--6406ec8a65a24fd785564006716b234d
6406ec8a65a24fd785564006716b234d--d78ce26eb9464ff9a1f6a24a3dc7704a
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 , 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 ]] )
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.0418+0.2231 j , 0.0432-0.1901 j , -0.0964+0.0036 j , -0.0887+0.2639 j ,
-0.7089-0.0307 j , -0.2299-0.2473 j , 0.0158+0.3053 j , 0.1789+0.2841 j ],
[ -0.0417+0.1488 j , -0.1586+0.4486 j , 0.0976+0.3513 j , -0.1487-0.2545 j ,
0.1258-0.2726 j , -0.4855-0.1732 j , -0.2351+0.0458 j , 0.1482-0.3078 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 )
├── X( 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 ]] )