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.01809663-0.99983624 j 0. + 0. j 0. + 0. 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_0a6b32fb99bb45c79da5aefd55f5b93e
Circuit block
cluster_b9ea93ae837045068d5b63cd7c6ac793
Prep block
3395f3e11b634dd6ae880c7e8ce821cd
0
d8c505d5762a45e7ac9d5b07d350d250
3395f3e11b634dd6ae880c7e8ce821cd--d8c505d5762a45e7ac9d5b07d350d250
b01be875bce64fdebb98c48465766b19
1
b192dcf6d9bf4ec19344509bb52726bb
RX(theta₀)
d8c505d5762a45e7ac9d5b07d350d250--b192dcf6d9bf4ec19344509bb52726bb
e9388fceb3e74ef585803b47a76090ce
RY(theta₄)
b192dcf6d9bf4ec19344509bb52726bb--e9388fceb3e74ef585803b47a76090ce
a183152b63e740db8e9bd0b9da0c99df
RX(theta₈)
e9388fceb3e74ef585803b47a76090ce--a183152b63e740db8e9bd0b9da0c99df
50aa66df7d214ee5adc06d31dc703a7f
a183152b63e740db8e9bd0b9da0c99df--50aa66df7d214ee5adc06d31dc703a7f
b46a4659b6aa44b7b6393050ef3ad8a7
50aa66df7d214ee5adc06d31dc703a7f--b46a4659b6aa44b7b6393050ef3ad8a7
3fb7a92dfd834ae0a342e870a4460432
RX(theta₁₂)
b46a4659b6aa44b7b6393050ef3ad8a7--3fb7a92dfd834ae0a342e870a4460432
8e676596852242109be29f2282f2a24e
RY(theta₁₆)
3fb7a92dfd834ae0a342e870a4460432--8e676596852242109be29f2282f2a24e
49f3749182c842f5bdac7507c044bb6a
RX(theta₂₀)
8e676596852242109be29f2282f2a24e--49f3749182c842f5bdac7507c044bb6a
279827d0cf6d4e3394ff21a161ca963c
49f3749182c842f5bdac7507c044bb6a--279827d0cf6d4e3394ff21a161ca963c
315f4c4edfc14f7d80e15aedd2c99a98
279827d0cf6d4e3394ff21a161ca963c--315f4c4edfc14f7d80e15aedd2c99a98
8f1c38c85efe493aa343a887c09fd7b8
315f4c4edfc14f7d80e15aedd2c99a98--8f1c38c85efe493aa343a887c09fd7b8
2a4f3f880e8d444da77001145b26bdc3
3c1d533b1d7a4dada3c7de39ac6aaadc
b01be875bce64fdebb98c48465766b19--3c1d533b1d7a4dada3c7de39ac6aaadc
3611ac2d67e241d2a0c53f2db7d1caf6
2
ae0a147f3eb74d2e865f38adb7e7ffa9
RX(theta₁)
3c1d533b1d7a4dada3c7de39ac6aaadc--ae0a147f3eb74d2e865f38adb7e7ffa9
b51b07f83d4944d595b8895a72f36bee
RY(theta₅)
ae0a147f3eb74d2e865f38adb7e7ffa9--b51b07f83d4944d595b8895a72f36bee
046cbbf4d632451f9d2166e20d0fc053
RX(theta₉)
b51b07f83d4944d595b8895a72f36bee--046cbbf4d632451f9d2166e20d0fc053
2f619de87c4c4c65b92dec8b46af7fc8
X
046cbbf4d632451f9d2166e20d0fc053--2f619de87c4c4c65b92dec8b46af7fc8
2f619de87c4c4c65b92dec8b46af7fc8--50aa66df7d214ee5adc06d31dc703a7f
bcf44f0223db4cb9a475fc48983d7b77
2f619de87c4c4c65b92dec8b46af7fc8--bcf44f0223db4cb9a475fc48983d7b77
5c99552e1c5740f698515f4cd98794d9
RX(theta₁₃)
bcf44f0223db4cb9a475fc48983d7b77--5c99552e1c5740f698515f4cd98794d9
2c96bfdc1cca42088eccbb1d71cdaa8a
RY(theta₁₇)
5c99552e1c5740f698515f4cd98794d9--2c96bfdc1cca42088eccbb1d71cdaa8a
e8fafd4f1d654006aa15c404075eaab2
RX(theta₂₁)
2c96bfdc1cca42088eccbb1d71cdaa8a--e8fafd4f1d654006aa15c404075eaab2
8634cb80c97f4c99b0d5fce47bbb599d
X
e8fafd4f1d654006aa15c404075eaab2--8634cb80c97f4c99b0d5fce47bbb599d
8634cb80c97f4c99b0d5fce47bbb599d--279827d0cf6d4e3394ff21a161ca963c
5f87f084820e470791459c3c70a17de8
8634cb80c97f4c99b0d5fce47bbb599d--5f87f084820e470791459c3c70a17de8
5f87f084820e470791459c3c70a17de8--2a4f3f880e8d444da77001145b26bdc3
63c9bdfc81bc4680a20655deb8817f7f
6905ff0dea0c47578ffdcf6a2393cd4b
3611ac2d67e241d2a0c53f2db7d1caf6--6905ff0dea0c47578ffdcf6a2393cd4b
7e4646f2ba444fd98f6bdbff6b82ea10
3
67f47cf0cbb34e42968662f8e94638ce
RX(theta₂)
6905ff0dea0c47578ffdcf6a2393cd4b--67f47cf0cbb34e42968662f8e94638ce
eaf1e1c4367144bcaa764d4b2951a4b0
RY(theta₆)
67f47cf0cbb34e42968662f8e94638ce--eaf1e1c4367144bcaa764d4b2951a4b0
aa6f3329433146c7aa2c41543a70010f
RX(theta₁₀)
eaf1e1c4367144bcaa764d4b2951a4b0--aa6f3329433146c7aa2c41543a70010f
64d74eb36be54f4e8db1a6a575f772a4
aa6f3329433146c7aa2c41543a70010f--64d74eb36be54f4e8db1a6a575f772a4
ccc84665bd0240749e16ecb6eaa58455
X
64d74eb36be54f4e8db1a6a575f772a4--ccc84665bd0240749e16ecb6eaa58455
ccc84665bd0240749e16ecb6eaa58455--bcf44f0223db4cb9a475fc48983d7b77
eb0d50aaee464199987a8a614ba8383b
RX(theta₁₄)
ccc84665bd0240749e16ecb6eaa58455--eb0d50aaee464199987a8a614ba8383b
4b5e9cecbdb64f6b833691c5d6f1f8d6
RY(theta₁₈)
eb0d50aaee464199987a8a614ba8383b--4b5e9cecbdb64f6b833691c5d6f1f8d6
e65768df075e40bda8e861756a5037e4
RX(theta₂₂)
4b5e9cecbdb64f6b833691c5d6f1f8d6--e65768df075e40bda8e861756a5037e4
870c2674b06d4648ab85364ff8d1b6de
e65768df075e40bda8e861756a5037e4--870c2674b06d4648ab85364ff8d1b6de
def1f895eabf470ca0902b7ad8860fe5
X
870c2674b06d4648ab85364ff8d1b6de--def1f895eabf470ca0902b7ad8860fe5
def1f895eabf470ca0902b7ad8860fe5--5f87f084820e470791459c3c70a17de8
def1f895eabf470ca0902b7ad8860fe5--63c9bdfc81bc4680a20655deb8817f7f
77c15032d8924f9884c2c28b39de4b97
514bf6d5bc2f4322ac831a0991c3c24f
X
7e4646f2ba444fd98f6bdbff6b82ea10--514bf6d5bc2f4322ac831a0991c3c24f
bff7b7daf9324c7db9af31ee2bdf3070
RX(theta₃)
514bf6d5bc2f4322ac831a0991c3c24f--bff7b7daf9324c7db9af31ee2bdf3070
3ec864544e1043d19da9c98308127315
RY(theta₇)
bff7b7daf9324c7db9af31ee2bdf3070--3ec864544e1043d19da9c98308127315
9e6f78f2dc0244419317777e3153db86
RX(theta₁₁)
3ec864544e1043d19da9c98308127315--9e6f78f2dc0244419317777e3153db86
798779952d074ce08425946b88f23944
X
9e6f78f2dc0244419317777e3153db86--798779952d074ce08425946b88f23944
798779952d074ce08425946b88f23944--64d74eb36be54f4e8db1a6a575f772a4
7bd1283132834a319b25dd2ed83fe358
798779952d074ce08425946b88f23944--7bd1283132834a319b25dd2ed83fe358
84fc4f7fb71c405a987e8df99a0f7f16
RX(theta₁₅)
7bd1283132834a319b25dd2ed83fe358--84fc4f7fb71c405a987e8df99a0f7f16
a5ae50fc756f4c1a9a7a62e9df4701a5
RY(theta₁₉)
84fc4f7fb71c405a987e8df99a0f7f16--a5ae50fc756f4c1a9a7a62e9df4701a5
b252f48bc10847b28ca4d96f05452d82
RX(theta₂₃)
a5ae50fc756f4c1a9a7a62e9df4701a5--b252f48bc10847b28ca4d96f05452d82
ea214093524b42c994aeb2ab39301901
X
b252f48bc10847b28ca4d96f05452d82--ea214093524b42c994aeb2ab39301901
ea214093524b42c994aeb2ab39301901--870c2674b06d4648ab85364ff8d1b6de
a4ca911d234847cb85dd724fa386d8ef
ea214093524b42c994aeb2ab39301901--a4ca911d234847cb85dd724fa386d8ef
a4ca911d234847cb85dd724fa386d8ef--77c15032d8924f9884c2c28b39de4b97
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 ],
[ 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 , 1.+0. j , 0.+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.2561-0.1032 j , 0.0494+0.0587 j , 0.3258+0.1880 j , 0.2518-0.0606 j ,
-0.3047-0.3365 j , -0.0829+0.4560 j , 0.2562+0.1226 j , -0.1817+0.4180 j ],
[ 0.3139+0.4935 j , -0.2357+0.3002 j , 0.4257+0.0696 j , 0.0326+0.0448 j ,
0.1226-0.1125 j , -0.2873+0.1443 j , -0.1797-0.3972 j , -0.0041-0.0452 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 ]] )
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 )
└── I( 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 ]] )