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.73685371+0.36294684 j 0.25202622-0.51166296 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 )
cluster_5a3bf50ff63c4ea7becf08bc290479f8
Circuit block
cluster_f34472f52ed8481bbf4ded593d1fb364
Prep block
1b088fa1c04d477aa3bddbdadd65196d
0
658b4036075c46ca8b46eee3efdfd147
1b088fa1c04d477aa3bddbdadd65196d--658b4036075c46ca8b46eee3efdfd147
bd10a44ccb754386a3a077440a1a8add
1
2ce3fd53cc064087beac24e85862a971
RX(theta₀)
658b4036075c46ca8b46eee3efdfd147--2ce3fd53cc064087beac24e85862a971
2475feb5056b4f4391d8babfff889476
RY(theta₄)
2ce3fd53cc064087beac24e85862a971--2475feb5056b4f4391d8babfff889476
ae645c3ba1b749dfa89a804e1978835a
RX(theta₈)
2475feb5056b4f4391d8babfff889476--ae645c3ba1b749dfa89a804e1978835a
d351c808507942a6aedc722872f45168
ae645c3ba1b749dfa89a804e1978835a--d351c808507942a6aedc722872f45168
0cb87358a1e440b6ad5c4019541516f4
d351c808507942a6aedc722872f45168--0cb87358a1e440b6ad5c4019541516f4
8220474b2e7e47d0a8c0af9259843cf7
RX(theta₁₂)
0cb87358a1e440b6ad5c4019541516f4--8220474b2e7e47d0a8c0af9259843cf7
85ffb65607f74ab88d21dd73e3723109
RY(theta₁₆)
8220474b2e7e47d0a8c0af9259843cf7--85ffb65607f74ab88d21dd73e3723109
ff0a16fea8804328ab71b00b56a3d669
RX(theta₂₀)
85ffb65607f74ab88d21dd73e3723109--ff0a16fea8804328ab71b00b56a3d669
41a8fbbde2f14c479d5d1ffede30b8be
ff0a16fea8804328ab71b00b56a3d669--41a8fbbde2f14c479d5d1ffede30b8be
f7b88391bb514833a6839e2833549d01
41a8fbbde2f14c479d5d1ffede30b8be--f7b88391bb514833a6839e2833549d01
5413d394364f409ab9f9ffcc68368365
f7b88391bb514833a6839e2833549d01--5413d394364f409ab9f9ffcc68368365
cebb78be9226493e998a887eba44dbc2
b5d6df3922754b469ff3923164d4628a
bd10a44ccb754386a3a077440a1a8add--b5d6df3922754b469ff3923164d4628a
c8d9064dc8fe44f39bd77de0fb29f7ac
2
388d0170bd254a9cad28be9a418d8b74
RX(theta₁)
b5d6df3922754b469ff3923164d4628a--388d0170bd254a9cad28be9a418d8b74
3dea7bdd524e46f2b125bcdc8bba93a0
RY(theta₅)
388d0170bd254a9cad28be9a418d8b74--3dea7bdd524e46f2b125bcdc8bba93a0
6d4a632e3f184e97945041af33b0ab45
RX(theta₉)
3dea7bdd524e46f2b125bcdc8bba93a0--6d4a632e3f184e97945041af33b0ab45
800e310ee14c41e88b30365e297521df
X
6d4a632e3f184e97945041af33b0ab45--800e310ee14c41e88b30365e297521df
800e310ee14c41e88b30365e297521df--d351c808507942a6aedc722872f45168
ff092d7492a143e1b063adc04424416a
800e310ee14c41e88b30365e297521df--ff092d7492a143e1b063adc04424416a
f05edf216ec04bb297b965db3d28791c
RX(theta₁₃)
ff092d7492a143e1b063adc04424416a--f05edf216ec04bb297b965db3d28791c
2e57b67b665c402ab61106acaf69578d
RY(theta₁₇)
f05edf216ec04bb297b965db3d28791c--2e57b67b665c402ab61106acaf69578d
a1233d3f96ba4c14ae0800e8c5b51139
RX(theta₂₁)
2e57b67b665c402ab61106acaf69578d--a1233d3f96ba4c14ae0800e8c5b51139
8489153457234930997995732cb5a27c
X
a1233d3f96ba4c14ae0800e8c5b51139--8489153457234930997995732cb5a27c
8489153457234930997995732cb5a27c--41a8fbbde2f14c479d5d1ffede30b8be
42b8ccc7f42c4aac947a331bc8719d4a
8489153457234930997995732cb5a27c--42b8ccc7f42c4aac947a331bc8719d4a
42b8ccc7f42c4aac947a331bc8719d4a--cebb78be9226493e998a887eba44dbc2
8bc29414100f4a6385ecdb4aa8e96d14
f966b00831294b06a88ec103130a5362
c8d9064dc8fe44f39bd77de0fb29f7ac--f966b00831294b06a88ec103130a5362
43effcde7bdd488f8e5b1863a921aa7e
3
f789fa1a9e4f4b1cb6de24403c05723e
RX(theta₂)
f966b00831294b06a88ec103130a5362--f789fa1a9e4f4b1cb6de24403c05723e
dac723f3e77f43768b8c385d07ad46c4
RY(theta₆)
f789fa1a9e4f4b1cb6de24403c05723e--dac723f3e77f43768b8c385d07ad46c4
6e5eeaf36f164baca14494c001d2e2c6
RX(theta₁₀)
dac723f3e77f43768b8c385d07ad46c4--6e5eeaf36f164baca14494c001d2e2c6
50a856f3bf10430e8a923c3f3435eda1
6e5eeaf36f164baca14494c001d2e2c6--50a856f3bf10430e8a923c3f3435eda1
af3bfa5bc3724fc0bce09ec4b8a9d7a1
X
50a856f3bf10430e8a923c3f3435eda1--af3bfa5bc3724fc0bce09ec4b8a9d7a1
af3bfa5bc3724fc0bce09ec4b8a9d7a1--ff092d7492a143e1b063adc04424416a
c0c571172c684f8a93ce71f8793b6385
RX(theta₁₄)
af3bfa5bc3724fc0bce09ec4b8a9d7a1--c0c571172c684f8a93ce71f8793b6385
af0c5246e51840888f6adb995c401101
RY(theta₁₈)
c0c571172c684f8a93ce71f8793b6385--af0c5246e51840888f6adb995c401101
d731d69129e549ea87d9293d43face44
RX(theta₂₂)
af0c5246e51840888f6adb995c401101--d731d69129e549ea87d9293d43face44
c54f7e58275248c4b553b4c5036c0f7d
d731d69129e549ea87d9293d43face44--c54f7e58275248c4b553b4c5036c0f7d
e12111c4e4e446f4a0012b8025dd65b2
X
c54f7e58275248c4b553b4c5036c0f7d--e12111c4e4e446f4a0012b8025dd65b2
e12111c4e4e446f4a0012b8025dd65b2--42b8ccc7f42c4aac947a331bc8719d4a
e12111c4e4e446f4a0012b8025dd65b2--8bc29414100f4a6385ecdb4aa8e96d14
08beb1d26d2b4a3b8c536d327de97479
42214aaf26f64705b7994138e25bb87c
X
43effcde7bdd488f8e5b1863a921aa7e--42214aaf26f64705b7994138e25bb87c
65fe5c27bc3a4f3cb532ea125709c19c
RX(theta₃)
42214aaf26f64705b7994138e25bb87c--65fe5c27bc3a4f3cb532ea125709c19c
0af93286f6754187a0ec699aa2ffee12
RY(theta₇)
65fe5c27bc3a4f3cb532ea125709c19c--0af93286f6754187a0ec699aa2ffee12
c9925c678955447b8652506e4cb123ee
RX(theta₁₁)
0af93286f6754187a0ec699aa2ffee12--c9925c678955447b8652506e4cb123ee
c785b6d8d34c45ee95b9dca98c4159c4
X
c9925c678955447b8652506e4cb123ee--c785b6d8d34c45ee95b9dca98c4159c4
c785b6d8d34c45ee95b9dca98c4159c4--50a856f3bf10430e8a923c3f3435eda1
b165cb6ea15c416ea6386d93d83d7392
c785b6d8d34c45ee95b9dca98c4159c4--b165cb6ea15c416ea6386d93d83d7392
d11b023edff2426e88f140dd45c7dd05
RX(theta₁₅)
b165cb6ea15c416ea6386d93d83d7392--d11b023edff2426e88f140dd45c7dd05
c5341e04407847c2a2258c54370f237b
RY(theta₁₉)
d11b023edff2426e88f140dd45c7dd05--c5341e04407847c2a2258c54370f237b
f1067e3ca73b414795713564038af403
RX(theta₂₃)
c5341e04407847c2a2258c54370f237b--f1067e3ca73b414795713564038af403
c0aa9c39df0c41d496ea95000888ea28
X
f1067e3ca73b414795713564038af403--c0aa9c39df0c41d496ea95000888ea28
c0aa9c39df0c41d496ea95000888ea28--c54f7e58275248c4b553b4c5036c0f7d
1554b74e54674447b750102d8f9e40ac
c0aa9c39df0c41d496ea95000888ea28--1554b74e54674447b750102d8f9e40ac
1554b74e54674447b750102d8f9e40ac--08beb1d26d2b4a3b8c536d327de97479
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 , 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 , 1.+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.3807+0.3202 j , -0.2349+0.0810 j , -0.3754+0.1022 j , 0.5541+0.2234 j ,
-0.1159+0.1347 j , -0.2595+0.1589 j , -0.1146-0.0531 j , -0.1842-0.0918 j ],
[ -0.2709+0.2965 j , -0.0363-0.1403 j , -0.0893+0.3857 j , -0.2192+0.0857 j ,
0.3617+0.1455 j , 0.2482-0.3901 j , 0.1752-0.3836 j , 0.1884-0.1628 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 )
├── X( 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 ]] )