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.99800534-0.06312957 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_6439ebfaaee547869e3c8fa74081380d
Circuit block
cluster_d214eab1b2d8495280501bc8b7bd88cc
Prep block
116ea58b89044aaa837504f0d539cac7
0
337752d18fd24102a9b112e77137fd45
116ea58b89044aaa837504f0d539cac7--337752d18fd24102a9b112e77137fd45
d31685fb0c094bf28e807a592c8bd2ff
1
6877809f33e94767b3946f2fa3a67596
RX(theta₀)
337752d18fd24102a9b112e77137fd45--6877809f33e94767b3946f2fa3a67596
638f762a01c2449aa011802a7ade3093
RY(theta₄)
6877809f33e94767b3946f2fa3a67596--638f762a01c2449aa011802a7ade3093
f24d2910ff6746e981834c5686dea3cc
RX(theta₈)
638f762a01c2449aa011802a7ade3093--f24d2910ff6746e981834c5686dea3cc
ecb7df6630ef4800b3868cecac9a34ad
f24d2910ff6746e981834c5686dea3cc--ecb7df6630ef4800b3868cecac9a34ad
4a4b5fce589d48a09e1321df65f257c7
ecb7df6630ef4800b3868cecac9a34ad--4a4b5fce589d48a09e1321df65f257c7
4db95bf4de4948928e008a90c1096dc5
RX(theta₁₂)
4a4b5fce589d48a09e1321df65f257c7--4db95bf4de4948928e008a90c1096dc5
71dc472694bb444eb0bfa6d3b7870e7d
RY(theta₁₆)
4db95bf4de4948928e008a90c1096dc5--71dc472694bb444eb0bfa6d3b7870e7d
bc3d426b365548eeb7cee81d8a05e4cf
RX(theta₂₀)
71dc472694bb444eb0bfa6d3b7870e7d--bc3d426b365548eeb7cee81d8a05e4cf
5be4933c610e4310b9d0a76e137427a5
bc3d426b365548eeb7cee81d8a05e4cf--5be4933c610e4310b9d0a76e137427a5
b2569b512d5c491aaa7023d9e771d48a
5be4933c610e4310b9d0a76e137427a5--b2569b512d5c491aaa7023d9e771d48a
80e87a35473e45bdb6b11a98f6584b2d
b2569b512d5c491aaa7023d9e771d48a--80e87a35473e45bdb6b11a98f6584b2d
7547a3c2feb04e3ea268e88cb8084f5a
2316561c62c6416ca619724029f660ad
d31685fb0c094bf28e807a592c8bd2ff--2316561c62c6416ca619724029f660ad
e2cc2c5281d1464c85655c9a12ceb656
2
fa368489e0574c8d8694b4e35892996a
RX(theta₁)
2316561c62c6416ca619724029f660ad--fa368489e0574c8d8694b4e35892996a
bd177c68d4b14524aaffc6468ebff58b
RY(theta₅)
fa368489e0574c8d8694b4e35892996a--bd177c68d4b14524aaffc6468ebff58b
08237cec9afe4361a60f125d1aa6bf71
RX(theta₉)
bd177c68d4b14524aaffc6468ebff58b--08237cec9afe4361a60f125d1aa6bf71
b99286c67e3e4c5583b137f70d6b8e8e
X
08237cec9afe4361a60f125d1aa6bf71--b99286c67e3e4c5583b137f70d6b8e8e
b99286c67e3e4c5583b137f70d6b8e8e--ecb7df6630ef4800b3868cecac9a34ad
77d01aeda232485c8be377192aca5f8a
b99286c67e3e4c5583b137f70d6b8e8e--77d01aeda232485c8be377192aca5f8a
8591dbca0d74435bb8965527d42899a0
RX(theta₁₃)
77d01aeda232485c8be377192aca5f8a--8591dbca0d74435bb8965527d42899a0
f202464a388c49ccb5c8dff59eda1c48
RY(theta₁₇)
8591dbca0d74435bb8965527d42899a0--f202464a388c49ccb5c8dff59eda1c48
29c96dee34bd4269a0ebc42acb220917
RX(theta₂₁)
f202464a388c49ccb5c8dff59eda1c48--29c96dee34bd4269a0ebc42acb220917
6be09711cfad44bab25fde69f884b944
X
29c96dee34bd4269a0ebc42acb220917--6be09711cfad44bab25fde69f884b944
6be09711cfad44bab25fde69f884b944--5be4933c610e4310b9d0a76e137427a5
98242f450f7a40ebbf9ac95bdc205c89
6be09711cfad44bab25fde69f884b944--98242f450f7a40ebbf9ac95bdc205c89
98242f450f7a40ebbf9ac95bdc205c89--7547a3c2feb04e3ea268e88cb8084f5a
70f303f351ec47129ba46ac68eded7cc
f9783f7e3f084b91b67717c9387049a0
e2cc2c5281d1464c85655c9a12ceb656--f9783f7e3f084b91b67717c9387049a0
be5fb09c7ce74c53bc4b06ea71d0611b
3
03493f3a1d3849d7bf8d06f409a1e79f
RX(theta₂)
f9783f7e3f084b91b67717c9387049a0--03493f3a1d3849d7bf8d06f409a1e79f
c99da835fb34430698c7f8facafe2ffb
RY(theta₆)
03493f3a1d3849d7bf8d06f409a1e79f--c99da835fb34430698c7f8facafe2ffb
5820f6f71858462f82173c64099430d3
RX(theta₁₀)
c99da835fb34430698c7f8facafe2ffb--5820f6f71858462f82173c64099430d3
a8d13243cda4407b9b549e89e6cc1775
5820f6f71858462f82173c64099430d3--a8d13243cda4407b9b549e89e6cc1775
235e7f4ef8e0495ebaa1b83ef601f67f
X
a8d13243cda4407b9b549e89e6cc1775--235e7f4ef8e0495ebaa1b83ef601f67f
235e7f4ef8e0495ebaa1b83ef601f67f--77d01aeda232485c8be377192aca5f8a
27daf186c40e4fb1ba40852da56a9de5
RX(theta₁₄)
235e7f4ef8e0495ebaa1b83ef601f67f--27daf186c40e4fb1ba40852da56a9de5
d82d692492f64690ac6cfd17e2289a72
RY(theta₁₈)
27daf186c40e4fb1ba40852da56a9de5--d82d692492f64690ac6cfd17e2289a72
1ed91d19e1c343cea3637c34c0cf36dd
RX(theta₂₂)
d82d692492f64690ac6cfd17e2289a72--1ed91d19e1c343cea3637c34c0cf36dd
4094b634ca784212b0b516524a0cb354
1ed91d19e1c343cea3637c34c0cf36dd--4094b634ca784212b0b516524a0cb354
ec7630b73fc745679eeed29d066a7eee
X
4094b634ca784212b0b516524a0cb354--ec7630b73fc745679eeed29d066a7eee
ec7630b73fc745679eeed29d066a7eee--98242f450f7a40ebbf9ac95bdc205c89
ec7630b73fc745679eeed29d066a7eee--70f303f351ec47129ba46ac68eded7cc
56f560d0fe534e1fb3e21cd097758677
cc450f2849bd4a2286a58e2177d4f3de
X
be5fb09c7ce74c53bc4b06ea71d0611b--cc450f2849bd4a2286a58e2177d4f3de
c0f622c8bcf9459fafd51c628394d238
RX(theta₃)
cc450f2849bd4a2286a58e2177d4f3de--c0f622c8bcf9459fafd51c628394d238
a37f358c994146ac9b4cfc059c8c65ef
RY(theta₇)
c0f622c8bcf9459fafd51c628394d238--a37f358c994146ac9b4cfc059c8c65ef
934a50000dcf4426b90d610fb78ad7e2
RX(theta₁₁)
a37f358c994146ac9b4cfc059c8c65ef--934a50000dcf4426b90d610fb78ad7e2
fbb776ff15174223a28a12bc7d9e1431
X
934a50000dcf4426b90d610fb78ad7e2--fbb776ff15174223a28a12bc7d9e1431
fbb776ff15174223a28a12bc7d9e1431--a8d13243cda4407b9b549e89e6cc1775
e2fda4757e7c4675b2f7eec45b1f8f61
fbb776ff15174223a28a12bc7d9e1431--e2fda4757e7c4675b2f7eec45b1f8f61
49fe0ee201984a9bb3291dc61767927f
RX(theta₁₅)
e2fda4757e7c4675b2f7eec45b1f8f61--49fe0ee201984a9bb3291dc61767927f
79040d6a0c6b44259be4594cca8f483f
RY(theta₁₉)
49fe0ee201984a9bb3291dc61767927f--79040d6a0c6b44259be4594cca8f483f
820e622199674e96811e184f741c8544
RX(theta₂₃)
79040d6a0c6b44259be4594cca8f483f--820e622199674e96811e184f741c8544
4e75eec39b554eb885237683704218b8
X
820e622199674e96811e184f741c8544--4e75eec39b554eb885237683704218b8
4e75eec39b554eb885237683704218b8--4094b634ca784212b0b516524a0cb354
196bc80424a04cc89c88dab4973d22eb
4e75eec39b554eb885237683704218b8--196bc80424a04cc89c88dab4973d22eb
196bc80424a04cc89c88dab4973d22eb--56f560d0fe534e1fb3e21cd097758677
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.0327-0.1023 j , -0.2824+0.1998 j , -0.1383+0.4078 j , 0.2924+0.2990 j ,
-0.0830+0.2405 j , 0.2116+0.4120 j , 0.3971+0.1071 j , 0.0651-0.2363 j ],
[ 0.0665-0.0104 j , 0.1020+0.0727 j , -0.0617-0.5360 j , 0.3180+0.3258 j ,
0.1026+0.2581 j , 0.2748+0.1173 j , -0.5009-0.1343 j , -0.1208-0.1774 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 )
└── 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 ]] )