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.96341538+0. j 0. + 0.16494296 j 0.20821588+0. j
0. + 0.03564791 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_690708cd681745b991df8fe0a55bce7d
Circuit block
cluster_315b03922c2249148d446608ea3bc381
Prep block
3b123206424a4306a75636cda2947546
0
554c63db03fa4e6b9c8c4c7eeac10060
3b123206424a4306a75636cda2947546--554c63db03fa4e6b9c8c4c7eeac10060
0bc32aa0e6714588ac60b936cf22f6fe
1
20fb8369265c4df2b6552da407674c3f
RX(theta₀)
554c63db03fa4e6b9c8c4c7eeac10060--20fb8369265c4df2b6552da407674c3f
b82d500c7cf346c1a28844b9ccea7e58
RY(theta₄)
20fb8369265c4df2b6552da407674c3f--b82d500c7cf346c1a28844b9ccea7e58
84abced678a14876b7a312a3805a32b2
RX(theta₈)
b82d500c7cf346c1a28844b9ccea7e58--84abced678a14876b7a312a3805a32b2
c78b47b213c24958b80ac9453cc29b1d
84abced678a14876b7a312a3805a32b2--c78b47b213c24958b80ac9453cc29b1d
f2a6ea3184334acdb3e7d364fa0afb37
c78b47b213c24958b80ac9453cc29b1d--f2a6ea3184334acdb3e7d364fa0afb37
43f3c3c2b8c84cb2a3ebcc47f1189e2b
RX(theta₁₂)
f2a6ea3184334acdb3e7d364fa0afb37--43f3c3c2b8c84cb2a3ebcc47f1189e2b
4d272b32c52a4bf4969d2423e7235da6
RY(theta₁₆)
43f3c3c2b8c84cb2a3ebcc47f1189e2b--4d272b32c52a4bf4969d2423e7235da6
56300d89bc744a1990a2bed12c236379
RX(theta₂₀)
4d272b32c52a4bf4969d2423e7235da6--56300d89bc744a1990a2bed12c236379
c3655607f7f94d3386971417470df767
56300d89bc744a1990a2bed12c236379--c3655607f7f94d3386971417470df767
4741f3d03e23441d927908442f73fec1
c3655607f7f94d3386971417470df767--4741f3d03e23441d927908442f73fec1
b1111219546049d9af62be8b05fd7cb3
4741f3d03e23441d927908442f73fec1--b1111219546049d9af62be8b05fd7cb3
60023fe8d1244128a306ac4b716f1513
a99facd950ef4e2bb0050da04c9c29e4
0bc32aa0e6714588ac60b936cf22f6fe--a99facd950ef4e2bb0050da04c9c29e4
bc868f0a6183420e86b9f362c677b44b
2
e961ff777a0b43a68c41819014f63eed
RX(theta₁)
a99facd950ef4e2bb0050da04c9c29e4--e961ff777a0b43a68c41819014f63eed
a112cf43472c4e37a9c70f910fbe2fb7
RY(theta₅)
e961ff777a0b43a68c41819014f63eed--a112cf43472c4e37a9c70f910fbe2fb7
56bcd4e3d93748a4bf5b93b7bed7f7e6
RX(theta₉)
a112cf43472c4e37a9c70f910fbe2fb7--56bcd4e3d93748a4bf5b93b7bed7f7e6
950a22da1238401d808b6e9b0157d8c0
X
56bcd4e3d93748a4bf5b93b7bed7f7e6--950a22da1238401d808b6e9b0157d8c0
950a22da1238401d808b6e9b0157d8c0--c78b47b213c24958b80ac9453cc29b1d
d32626d8752e449b80eecd904b0f53de
950a22da1238401d808b6e9b0157d8c0--d32626d8752e449b80eecd904b0f53de
5ca7eb2b39ca4af4b181a102b51c3d40
RX(theta₁₃)
d32626d8752e449b80eecd904b0f53de--5ca7eb2b39ca4af4b181a102b51c3d40
0e1913fa89354f4a8d9cd1a622a61770
RY(theta₁₇)
5ca7eb2b39ca4af4b181a102b51c3d40--0e1913fa89354f4a8d9cd1a622a61770
994d7397e0cd4c819512ee3f0683823c
RX(theta₂₁)
0e1913fa89354f4a8d9cd1a622a61770--994d7397e0cd4c819512ee3f0683823c
ae2adbb9bf7a4a27a3d4ed6f92a34fdc
X
994d7397e0cd4c819512ee3f0683823c--ae2adbb9bf7a4a27a3d4ed6f92a34fdc
ae2adbb9bf7a4a27a3d4ed6f92a34fdc--c3655607f7f94d3386971417470df767
99989b1082f4482d9372e7f18c75175a
ae2adbb9bf7a4a27a3d4ed6f92a34fdc--99989b1082f4482d9372e7f18c75175a
99989b1082f4482d9372e7f18c75175a--60023fe8d1244128a306ac4b716f1513
da079a9fb13946e9b30995e305778100
dd68e0fc02f345bf91f02685fd8d4fa4
bc868f0a6183420e86b9f362c677b44b--dd68e0fc02f345bf91f02685fd8d4fa4
652bbbe731df4eda9bf814b30740e3dc
3
c9b1bacde9c04f77856234dbd1f37112
RX(theta₂)
dd68e0fc02f345bf91f02685fd8d4fa4--c9b1bacde9c04f77856234dbd1f37112
da2b6f9561ea43ecb624a0abad7a2d97
RY(theta₆)
c9b1bacde9c04f77856234dbd1f37112--da2b6f9561ea43ecb624a0abad7a2d97
5356fa8bac094c068ce51fa29346fe83
RX(theta₁₀)
da2b6f9561ea43ecb624a0abad7a2d97--5356fa8bac094c068ce51fa29346fe83
af449c1928c0401fb02b1397a32c9da1
5356fa8bac094c068ce51fa29346fe83--af449c1928c0401fb02b1397a32c9da1
072770291ade4e5e8dd92e756db94199
X
af449c1928c0401fb02b1397a32c9da1--072770291ade4e5e8dd92e756db94199
072770291ade4e5e8dd92e756db94199--d32626d8752e449b80eecd904b0f53de
f55c80e86ddf4cfb9caa0bd7948806c2
RX(theta₁₄)
072770291ade4e5e8dd92e756db94199--f55c80e86ddf4cfb9caa0bd7948806c2
1696e2cda28e4f5cb78b4ee5442d9cf7
RY(theta₁₈)
f55c80e86ddf4cfb9caa0bd7948806c2--1696e2cda28e4f5cb78b4ee5442d9cf7
e87d020df4b142e093eae80628947343
RX(theta₂₂)
1696e2cda28e4f5cb78b4ee5442d9cf7--e87d020df4b142e093eae80628947343
47eba224cc7444c7a60eee34d336ac4d
e87d020df4b142e093eae80628947343--47eba224cc7444c7a60eee34d336ac4d
a085d7bba17447c2abe814735839ab06
X
47eba224cc7444c7a60eee34d336ac4d--a085d7bba17447c2abe814735839ab06
a085d7bba17447c2abe814735839ab06--99989b1082f4482d9372e7f18c75175a
a085d7bba17447c2abe814735839ab06--da079a9fb13946e9b30995e305778100
df310504f1be414ebb1a93d14055c86f
e51f8b1409144271812eca1c966ac197
X
652bbbe731df4eda9bf814b30740e3dc--e51f8b1409144271812eca1c966ac197
20c041d45e454c04bf413a38fadcb972
RX(theta₃)
e51f8b1409144271812eca1c966ac197--20c041d45e454c04bf413a38fadcb972
f4268f58a0fd4477a75c6092377f7ad6
RY(theta₇)
20c041d45e454c04bf413a38fadcb972--f4268f58a0fd4477a75c6092377f7ad6
15fafac5f3a64263bcbad5bcedd5cc57
RX(theta₁₁)
f4268f58a0fd4477a75c6092377f7ad6--15fafac5f3a64263bcbad5bcedd5cc57
450e5c9b5b024a218180b3acc07802ed
X
15fafac5f3a64263bcbad5bcedd5cc57--450e5c9b5b024a218180b3acc07802ed
450e5c9b5b024a218180b3acc07802ed--af449c1928c0401fb02b1397a32c9da1
f29696139f704453b82f4d6c3c6e8ab1
450e5c9b5b024a218180b3acc07802ed--f29696139f704453b82f4d6c3c6e8ab1
ff08004940ad43eb8ac5a2570d93eca1
RX(theta₁₅)
f29696139f704453b82f4d6c3c6e8ab1--ff08004940ad43eb8ac5a2570d93eca1
ee728db15d0443aab851529d5a42aeb9
RY(theta₁₉)
ff08004940ad43eb8ac5a2570d93eca1--ee728db15d0443aab851529d5a42aeb9
7ab6e23e8e944395b55fbe207fc002a9
RX(theta₂₃)
ee728db15d0443aab851529d5a42aeb9--7ab6e23e8e944395b55fbe207fc002a9
f2a9cfe6a3d44de9948106349b55b88b
X
7ab6e23e8e944395b55fbe207fc002a9--f2a9cfe6a3d44de9948106349b55b88b
f2a9cfe6a3d44de9948106349b55b88b--47eba224cc7444c7a60eee34d336ac4d
464331225d1e4b7e91ef62f8954ea339
f2a9cfe6a3d44de9948106349b55b88b--464331225d1e4b7e91ef62f8954ea339
464331225d1e4b7e91ef62f8954ea339--df310504f1be414ebb1a93d14055c86f
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 , 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 , 0.+0. j , 1.+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.2142+0.1216 j , -0.0990+0.2213 j , 0.1671+0.4044 j , -0.2842-0.4005 j ,
0.0661-0.0810 j , -0.2227-0.4556 j , -0.1442-0.0752 j , -0.3208-0.2246 j ],
[ -0.0095+0.6175 j , 0.4006-0.0110 j , -0.0621-0.1283 j , -0.0106-0.2222 j ,
-0.3444-0.4034 j , -0.0364+0.0958 j , -0.0517-0.1274 j , 0.0586+0.2720 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 ]] )