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.86909607+0. j 0.48486511+0. j -0.08546558+0. j -0.0476809 + 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_73c1e9b3c71c4e02973a86ab24c31b28
Circuit block
cluster_7a0e1a60565649339e4980880e7966ec
Prep block
afcbe6bbab054ff0bff29bbdc4a296b0
0
8fa9be296be84173bdf1836cc2f573a2
afcbe6bbab054ff0bff29bbdc4a296b0--8fa9be296be84173bdf1836cc2f573a2
899410a8ad17425eb442348c0135f437
1
9304be08ee8d4d12ba2f46dc8867377f
RX(theta₀)
8fa9be296be84173bdf1836cc2f573a2--9304be08ee8d4d12ba2f46dc8867377f
92a547a033cb48bb9a3a7210749b321e
RY(theta₄)
9304be08ee8d4d12ba2f46dc8867377f--92a547a033cb48bb9a3a7210749b321e
9589523dfb644e4eb4ed919c9138750e
RX(theta₈)
92a547a033cb48bb9a3a7210749b321e--9589523dfb644e4eb4ed919c9138750e
439c4fafb3994212959c721127431ef2
9589523dfb644e4eb4ed919c9138750e--439c4fafb3994212959c721127431ef2
b91a4a066e6e468680d06ae52c871640
439c4fafb3994212959c721127431ef2--b91a4a066e6e468680d06ae52c871640
bfe153fcaf724999af5e9bfcb3b467e3
RX(theta₁₂)
b91a4a066e6e468680d06ae52c871640--bfe153fcaf724999af5e9bfcb3b467e3
168762f885c84451bee4665779e29dae
RY(theta₁₆)
bfe153fcaf724999af5e9bfcb3b467e3--168762f885c84451bee4665779e29dae
49ddc56bae9f4662b2fbe2f3695dad71
RX(theta₂₀)
168762f885c84451bee4665779e29dae--49ddc56bae9f4662b2fbe2f3695dad71
bbb3b3af8e73499fbb29ed168d07c4d4
49ddc56bae9f4662b2fbe2f3695dad71--bbb3b3af8e73499fbb29ed168d07c4d4
0cd41a185a774a428508fc74081fc86b
bbb3b3af8e73499fbb29ed168d07c4d4--0cd41a185a774a428508fc74081fc86b
2b74daf7c77b4b0f9674b767b9af732e
0cd41a185a774a428508fc74081fc86b--2b74daf7c77b4b0f9674b767b9af732e
e6d61d9bf069406ba22b7dc6ee84a434
9993d886346a4500a017c3061af59639
899410a8ad17425eb442348c0135f437--9993d886346a4500a017c3061af59639
1a9b2533b2d24b39a38eccf74fd67332
2
e0c419b74c314436a26f8fd4f0b2091d
RX(theta₁)
9993d886346a4500a017c3061af59639--e0c419b74c314436a26f8fd4f0b2091d
0bdeccf339344fda9f02c9ab6360d8ba
RY(theta₅)
e0c419b74c314436a26f8fd4f0b2091d--0bdeccf339344fda9f02c9ab6360d8ba
94e4a6402fde48b080c50be4339540ca
RX(theta₉)
0bdeccf339344fda9f02c9ab6360d8ba--94e4a6402fde48b080c50be4339540ca
cc615c31046f48ca9f636dd6fa20a866
X
94e4a6402fde48b080c50be4339540ca--cc615c31046f48ca9f636dd6fa20a866
cc615c31046f48ca9f636dd6fa20a866--439c4fafb3994212959c721127431ef2
1dd6688fea024c398adf6470f06f7447
cc615c31046f48ca9f636dd6fa20a866--1dd6688fea024c398adf6470f06f7447
5807187dd5fa4b6abbd5354504d9cab2
RX(theta₁₃)
1dd6688fea024c398adf6470f06f7447--5807187dd5fa4b6abbd5354504d9cab2
793c7059d6b64961b34956406e8323e2
RY(theta₁₇)
5807187dd5fa4b6abbd5354504d9cab2--793c7059d6b64961b34956406e8323e2
8d1ab062ab874e90b3d2d0c582404357
RX(theta₂₁)
793c7059d6b64961b34956406e8323e2--8d1ab062ab874e90b3d2d0c582404357
125a7681a01046c491e3fab4c65f80d1
X
8d1ab062ab874e90b3d2d0c582404357--125a7681a01046c491e3fab4c65f80d1
125a7681a01046c491e3fab4c65f80d1--bbb3b3af8e73499fbb29ed168d07c4d4
6b10607c6f8b43a29b005493d20717c8
125a7681a01046c491e3fab4c65f80d1--6b10607c6f8b43a29b005493d20717c8
6b10607c6f8b43a29b005493d20717c8--e6d61d9bf069406ba22b7dc6ee84a434
c710e97d09b54afea1f709f86543de43
b01d498ef6fd472c822200683bde7c6f
1a9b2533b2d24b39a38eccf74fd67332--b01d498ef6fd472c822200683bde7c6f
60211833675045f4b0f545e5dc7615c9
3
14b7fd69226e463a94f04a74f5bc0729
RX(theta₂)
b01d498ef6fd472c822200683bde7c6f--14b7fd69226e463a94f04a74f5bc0729
f0ddcac3e1aa4c78bba36073113678b8
RY(theta₆)
14b7fd69226e463a94f04a74f5bc0729--f0ddcac3e1aa4c78bba36073113678b8
0aae466d5ef146f8a2940065e28ed9d7
RX(theta₁₀)
f0ddcac3e1aa4c78bba36073113678b8--0aae466d5ef146f8a2940065e28ed9d7
a534d2c655624393b88af57f5b05e280
0aae466d5ef146f8a2940065e28ed9d7--a534d2c655624393b88af57f5b05e280
1782855c511f4426aeb03b011e6c95ed
X
a534d2c655624393b88af57f5b05e280--1782855c511f4426aeb03b011e6c95ed
1782855c511f4426aeb03b011e6c95ed--1dd6688fea024c398adf6470f06f7447
a54d1fb7a63b43aa83aab1d3ace36768
RX(theta₁₄)
1782855c511f4426aeb03b011e6c95ed--a54d1fb7a63b43aa83aab1d3ace36768
7c6343d236544da1847d0c5f5587addd
RY(theta₁₈)
a54d1fb7a63b43aa83aab1d3ace36768--7c6343d236544da1847d0c5f5587addd
19060c44bb9c45df883cdd01f5208a1e
RX(theta₂₂)
7c6343d236544da1847d0c5f5587addd--19060c44bb9c45df883cdd01f5208a1e
a26664b2bd734f9e84d4e795754b0c3b
19060c44bb9c45df883cdd01f5208a1e--a26664b2bd734f9e84d4e795754b0c3b
fa22feb660cc48fea5b24e34031d7098
X
a26664b2bd734f9e84d4e795754b0c3b--fa22feb660cc48fea5b24e34031d7098
fa22feb660cc48fea5b24e34031d7098--6b10607c6f8b43a29b005493d20717c8
fa22feb660cc48fea5b24e34031d7098--c710e97d09b54afea1f709f86543de43
9c962614efc6470693772856c105b69d
6c9b127801744440b1f060be8eac5e1c
X
60211833675045f4b0f545e5dc7615c9--6c9b127801744440b1f060be8eac5e1c
206ef64717ac4653a46eadf6b3894757
RX(theta₃)
6c9b127801744440b1f060be8eac5e1c--206ef64717ac4653a46eadf6b3894757
d7239c8fdbf84aababc8e0fd6c67285a
RY(theta₇)
206ef64717ac4653a46eadf6b3894757--d7239c8fdbf84aababc8e0fd6c67285a
308c6d9aa1864508ad0441eeab4eca12
RX(theta₁₁)
d7239c8fdbf84aababc8e0fd6c67285a--308c6d9aa1864508ad0441eeab4eca12
11ba1e3274d64e17b67de868c17d0fca
X
308c6d9aa1864508ad0441eeab4eca12--11ba1e3274d64e17b67de868c17d0fca
11ba1e3274d64e17b67de868c17d0fca--a534d2c655624393b88af57f5b05e280
f1d215b304e649cc85f9d4c434c0ef30
11ba1e3274d64e17b67de868c17d0fca--f1d215b304e649cc85f9d4c434c0ef30
9761bd09490b4be88a1bbc90a2453b4e
RX(theta₁₅)
f1d215b304e649cc85f9d4c434c0ef30--9761bd09490b4be88a1bbc90a2453b4e
535fa61903b34b5f80a5ace6a4b101b4
RY(theta₁₉)
9761bd09490b4be88a1bbc90a2453b4e--535fa61903b34b5f80a5ace6a4b101b4
3abd46ad66474dc9878b1fb2638b2d50
RX(theta₂₃)
535fa61903b34b5f80a5ace6a4b101b4--3abd46ad66474dc9878b1fb2638b2d50
078e6d29e1cd4888843f995bc7efcf5a
X
3abd46ad66474dc9878b1fb2638b2d50--078e6d29e1cd4888843f995bc7efcf5a
078e6d29e1cd4888843f995bc7efcf5a--a26664b2bd734f9e84d4e795754b0c3b
92f6703d38234325b41336acb848a500
078e6d29e1cd4888843f995bc7efcf5a--92f6703d38234325b41336acb848a500
92f6703d38234325b41336acb848a500--9c962614efc6470693772856c105b69d
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 , 1.+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 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.2770+0.1293 j , -0.0215-0.1989 j , -0.0059-0.1722 j , -0.0701-0.5453 j ,
0.1952-0.2482 j , 0.0533-0.1674 j , 0.3690+0.2146 j , 0.3263+0.3397 j ],
[ 0.3077+0.1175 j , -0.0426-0.1098 j , 0.0193-0.5347 j , 0.3126-0.4919 j ,
-0.0170+0.0276 j , -0.2911+0.3312 j , -0.1317-0.0877 j , -0.0230+0.1749 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 )
├── X( 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 ]] )