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.90828256+0. j 0.38695419+0. j -0.14630225+0. j -0.06232892+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_01d1b066e778484ea674561155bf1f8f
Circuit block
cluster_4eaf5ad3872b4396845c424ee25bbab1
Prep block
a57fb329edb1431d9ffbb41d3078b8f7
0
bae1df517ae24c13b99af9fd546acc53
a57fb329edb1431d9ffbb41d3078b8f7--bae1df517ae24c13b99af9fd546acc53
64ef8db7e3904cde9aea2017f007767f
1
ad2d61dd501742669656bddf25160190
RX(theta₀)
bae1df517ae24c13b99af9fd546acc53--ad2d61dd501742669656bddf25160190
b635e95e9b2c4447a32ce3b602a720c9
RY(theta₄)
ad2d61dd501742669656bddf25160190--b635e95e9b2c4447a32ce3b602a720c9
8e90952768d2494699682485dcaea8cf
RX(theta₈)
b635e95e9b2c4447a32ce3b602a720c9--8e90952768d2494699682485dcaea8cf
cf572c032cca4d40bd9349acd5688749
8e90952768d2494699682485dcaea8cf--cf572c032cca4d40bd9349acd5688749
8d183f0ad4f241c99bde8b7f399e5019
cf572c032cca4d40bd9349acd5688749--8d183f0ad4f241c99bde8b7f399e5019
d8d6f270f68d499390c8b4869e25d447
RX(theta₁₂)
8d183f0ad4f241c99bde8b7f399e5019--d8d6f270f68d499390c8b4869e25d447
f7e70f1cc88e4774a9e7c72d0ab77cf7
RY(theta₁₆)
d8d6f270f68d499390c8b4869e25d447--f7e70f1cc88e4774a9e7c72d0ab77cf7
e114418a76164b00aaf0d769e4ea0d7c
RX(theta₂₀)
f7e70f1cc88e4774a9e7c72d0ab77cf7--e114418a76164b00aaf0d769e4ea0d7c
de8dfe8691a34843b329c144393bd61b
e114418a76164b00aaf0d769e4ea0d7c--de8dfe8691a34843b329c144393bd61b
d3b06b9aff5f405cae36f5bb11008451
de8dfe8691a34843b329c144393bd61b--d3b06b9aff5f405cae36f5bb11008451
f8bb563e42ce42dba3da4b543d6ce5a3
d3b06b9aff5f405cae36f5bb11008451--f8bb563e42ce42dba3da4b543d6ce5a3
fc875c4e1b034bd9bb3ba73af3a3deb3
5e3028319019422a9dc6df9aa519c150
64ef8db7e3904cde9aea2017f007767f--5e3028319019422a9dc6df9aa519c150
7c7a4e8daf224351890428b191b0a31e
2
5ecca52c92c540a2aa1a673f40b03259
RX(theta₁)
5e3028319019422a9dc6df9aa519c150--5ecca52c92c540a2aa1a673f40b03259
ad44d3f03f334be0b4b672ee8a940d30
RY(theta₅)
5ecca52c92c540a2aa1a673f40b03259--ad44d3f03f334be0b4b672ee8a940d30
f5aaeda0e0c840ecb7522f5921df40af
RX(theta₉)
ad44d3f03f334be0b4b672ee8a940d30--f5aaeda0e0c840ecb7522f5921df40af
5bbd61a7036c4d28aa60c62bc7d8a87f
X
f5aaeda0e0c840ecb7522f5921df40af--5bbd61a7036c4d28aa60c62bc7d8a87f
5bbd61a7036c4d28aa60c62bc7d8a87f--cf572c032cca4d40bd9349acd5688749
ca3f8d3531e04a558d744da0015e560a
5bbd61a7036c4d28aa60c62bc7d8a87f--ca3f8d3531e04a558d744da0015e560a
39c4b2ae3a364718a74d5e6a1d3e5f18
RX(theta₁₃)
ca3f8d3531e04a558d744da0015e560a--39c4b2ae3a364718a74d5e6a1d3e5f18
949e448f5eda4550b9d997ccd4d0b320
RY(theta₁₇)
39c4b2ae3a364718a74d5e6a1d3e5f18--949e448f5eda4550b9d997ccd4d0b320
0c36cbf4fc2542b280f4d9a573795135
RX(theta₂₁)
949e448f5eda4550b9d997ccd4d0b320--0c36cbf4fc2542b280f4d9a573795135
ccbcc66e0dc04b269a05371c595ce78b
X
0c36cbf4fc2542b280f4d9a573795135--ccbcc66e0dc04b269a05371c595ce78b
ccbcc66e0dc04b269a05371c595ce78b--de8dfe8691a34843b329c144393bd61b
6083a122dec74fc388f6c97edc91d683
ccbcc66e0dc04b269a05371c595ce78b--6083a122dec74fc388f6c97edc91d683
6083a122dec74fc388f6c97edc91d683--fc875c4e1b034bd9bb3ba73af3a3deb3
75c8c5a367754b2c83cd96356312d6a7
3b03a925bad54162968644c357c3c75a
7c7a4e8daf224351890428b191b0a31e--3b03a925bad54162968644c357c3c75a
3b38a25c1c5f4f10b3284518655c4e26
3
98f6494a498c457a9e11ff7e1046058c
RX(theta₂)
3b03a925bad54162968644c357c3c75a--98f6494a498c457a9e11ff7e1046058c
7ae4fc215d2b403a91803bdd5c485aa9
RY(theta₆)
98f6494a498c457a9e11ff7e1046058c--7ae4fc215d2b403a91803bdd5c485aa9
63812114966746a98a58ba165af995c9
RX(theta₁₀)
7ae4fc215d2b403a91803bdd5c485aa9--63812114966746a98a58ba165af995c9
e055b4556b6c4c4ab333404c92be8b9d
63812114966746a98a58ba165af995c9--e055b4556b6c4c4ab333404c92be8b9d
8c791f150ad04a948fcf0eed008c43fa
X
e055b4556b6c4c4ab333404c92be8b9d--8c791f150ad04a948fcf0eed008c43fa
8c791f150ad04a948fcf0eed008c43fa--ca3f8d3531e04a558d744da0015e560a
127d602ca1a8403ca10604b51f988f33
RX(theta₁₄)
8c791f150ad04a948fcf0eed008c43fa--127d602ca1a8403ca10604b51f988f33
5b54a0c766194c18a68aac94c9e7da66
RY(theta₁₈)
127d602ca1a8403ca10604b51f988f33--5b54a0c766194c18a68aac94c9e7da66
a97a517b292c41a7987eb5420707c2ee
RX(theta₂₂)
5b54a0c766194c18a68aac94c9e7da66--a97a517b292c41a7987eb5420707c2ee
dd126008ac41469da6b45ab022db0b9e
a97a517b292c41a7987eb5420707c2ee--dd126008ac41469da6b45ab022db0b9e
417979b55cae4e45bb46914730c6ebd8
X
dd126008ac41469da6b45ab022db0b9e--417979b55cae4e45bb46914730c6ebd8
417979b55cae4e45bb46914730c6ebd8--6083a122dec74fc388f6c97edc91d683
417979b55cae4e45bb46914730c6ebd8--75c8c5a367754b2c83cd96356312d6a7
bbf98e41c0d94129a12c59690057c670
a2a2529117a74561a246585eeb32e434
X
3b38a25c1c5f4f10b3284518655c4e26--a2a2529117a74561a246585eeb32e434
0e232c19111a480b98fd81246cd03194
RX(theta₃)
a2a2529117a74561a246585eeb32e434--0e232c19111a480b98fd81246cd03194
b56959160c35414d8cc6617572e66173
RY(theta₇)
0e232c19111a480b98fd81246cd03194--b56959160c35414d8cc6617572e66173
8e45e17bee88445cbdd25a6f41cd7a9d
RX(theta₁₁)
b56959160c35414d8cc6617572e66173--8e45e17bee88445cbdd25a6f41cd7a9d
4fabc53316864a13a48be799f0bfc476
X
8e45e17bee88445cbdd25a6f41cd7a9d--4fabc53316864a13a48be799f0bfc476
4fabc53316864a13a48be799f0bfc476--e055b4556b6c4c4ab333404c92be8b9d
69df454064974e52a3103ae2cc2aa643
4fabc53316864a13a48be799f0bfc476--69df454064974e52a3103ae2cc2aa643
9cfe76535f5c4144a36f6f0fd7bb0fec
RX(theta₁₅)
69df454064974e52a3103ae2cc2aa643--9cfe76535f5c4144a36f6f0fd7bb0fec
71b1632163f547e9abb820049eb9ff01
RY(theta₁₉)
9cfe76535f5c4144a36f6f0fd7bb0fec--71b1632163f547e9abb820049eb9ff01
742924a57a404a6bb3b7c099b7e51718
RX(theta₂₃)
71b1632163f547e9abb820049eb9ff01--742924a57a404a6bb3b7c099b7e51718
c045ad218622423e995e2b5672cee9d1
X
742924a57a404a6bb3b7c099b7e51718--c045ad218622423e995e2b5672cee9d1
c045ad218622423e995e2b5672cee9d1--dd126008ac41469da6b45ab022db0b9e
3fa50c272603409d9407e97f87ce6070
c045ad218622423e995e2b5672cee9d1--3fa50c272603409d9407e97f87ce6070
3fa50c272603409d9407e97f87ce6070--bbf98e41c0d94129a12c59690057c670
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 , 0.+0. j , 1.+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.0824+0.4787 j , -0.0539-0.1946 j , 0.1156+0.4589 j , 0.1344-0.2154 j ,
-0.2126+0.3212 j , -0.0655+0.3265 j , 0.0400+0.1130 j , 0.3646-0.1686 j ],
[ -0.0259-0.2140 j , -0.3231-0.1988 j , 0.0704-0.4587 j , 0.4639-0.0569 j ,
-0.2917-0.2823 j , 0.1924+0.2168 j , -0.0910+0.0082 j , 0.3097-0.1508 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 ]] )