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.45600936-0.30375134 j 0. + 0. j 0.69621865-0.46375659 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_1470f093a2614456bb63468ce533dbf8
Circuit block
cluster_7732a9e748b04b2b9cbdcc364bee83d2
Prep block
d63a14db489c4bb896ff39c412caaf50
0
fbfd4821c30f48359169c6d13c09ab50
d63a14db489c4bb896ff39c412caaf50--fbfd4821c30f48359169c6d13c09ab50
d92c9688af524a9d947e4831af580c19
1
527e9a5960f64a2fa0e6b80a0287ef5e
RX(theta₀)
fbfd4821c30f48359169c6d13c09ab50--527e9a5960f64a2fa0e6b80a0287ef5e
4b294d579c5149c59dfff9474fe928dd
RY(theta₄)
527e9a5960f64a2fa0e6b80a0287ef5e--4b294d579c5149c59dfff9474fe928dd
bdab414212b34eaab6c1f6e237e563a3
RX(theta₈)
4b294d579c5149c59dfff9474fe928dd--bdab414212b34eaab6c1f6e237e563a3
f6e49552e5d64f89b09960b704e5317c
bdab414212b34eaab6c1f6e237e563a3--f6e49552e5d64f89b09960b704e5317c
503c69bbcbc54d10a6c69c3def479093
f6e49552e5d64f89b09960b704e5317c--503c69bbcbc54d10a6c69c3def479093
257fa4ce6a664fc3a3e8020294a26624
RX(theta₁₂)
503c69bbcbc54d10a6c69c3def479093--257fa4ce6a664fc3a3e8020294a26624
dff5294bd59b498a89b781eb47b69562
RY(theta₁₆)
257fa4ce6a664fc3a3e8020294a26624--dff5294bd59b498a89b781eb47b69562
022c1410ba1946eaa86002fe39caa0f2
RX(theta₂₀)
dff5294bd59b498a89b781eb47b69562--022c1410ba1946eaa86002fe39caa0f2
728ee556f2bb455e824e7dd9bac4c87a
022c1410ba1946eaa86002fe39caa0f2--728ee556f2bb455e824e7dd9bac4c87a
60f54b6068c6427b98e6e06340fe47a9
728ee556f2bb455e824e7dd9bac4c87a--60f54b6068c6427b98e6e06340fe47a9
581628ad3f3942d98df3fed234aa9f8e
60f54b6068c6427b98e6e06340fe47a9--581628ad3f3942d98df3fed234aa9f8e
df0be16186ae4472aefebb71425f7784
2385913ddd4c4704bd28cb2d34966821
d92c9688af524a9d947e4831af580c19--2385913ddd4c4704bd28cb2d34966821
d0e22f55040c467cb10c2151ebb6b920
2
854d65ad89e24ac58fbb0d2cd6e053d0
RX(theta₁)
2385913ddd4c4704bd28cb2d34966821--854d65ad89e24ac58fbb0d2cd6e053d0
a338bc3e53414ac2bf1665b5a13de5d7
RY(theta₅)
854d65ad89e24ac58fbb0d2cd6e053d0--a338bc3e53414ac2bf1665b5a13de5d7
08d98fe1db6a4b7b8b60a92cadd06ed7
RX(theta₉)
a338bc3e53414ac2bf1665b5a13de5d7--08d98fe1db6a4b7b8b60a92cadd06ed7
c8becf221fbb46978fdc148323cdaa4e
X
08d98fe1db6a4b7b8b60a92cadd06ed7--c8becf221fbb46978fdc148323cdaa4e
c8becf221fbb46978fdc148323cdaa4e--f6e49552e5d64f89b09960b704e5317c
b88d4001c78942b8890e08d5e7aca18a
c8becf221fbb46978fdc148323cdaa4e--b88d4001c78942b8890e08d5e7aca18a
feee3fc285b945a09903d4b9400fe136
RX(theta₁₃)
b88d4001c78942b8890e08d5e7aca18a--feee3fc285b945a09903d4b9400fe136
24239aa7f0d04c9dacda6f19d43058c0
RY(theta₁₇)
feee3fc285b945a09903d4b9400fe136--24239aa7f0d04c9dacda6f19d43058c0
5b86f62d2f2e4e4e80d12dcfca7cee4e
RX(theta₂₁)
24239aa7f0d04c9dacda6f19d43058c0--5b86f62d2f2e4e4e80d12dcfca7cee4e
6e5cf0e6a1c246878ab79aea96bd5783
X
5b86f62d2f2e4e4e80d12dcfca7cee4e--6e5cf0e6a1c246878ab79aea96bd5783
6e5cf0e6a1c246878ab79aea96bd5783--728ee556f2bb455e824e7dd9bac4c87a
1f51b4b4993a4f9f9f75337814536573
6e5cf0e6a1c246878ab79aea96bd5783--1f51b4b4993a4f9f9f75337814536573
1f51b4b4993a4f9f9f75337814536573--df0be16186ae4472aefebb71425f7784
db03575d38f4462786ff4c843a69e245
d1f1a55907f3410daf10496aa5acbc0d
d0e22f55040c467cb10c2151ebb6b920--d1f1a55907f3410daf10496aa5acbc0d
e316aba485864a01b4cdb79417dc36cf
3
858e55d5a1a446b0bc1fbf0b2fce419b
RX(theta₂)
d1f1a55907f3410daf10496aa5acbc0d--858e55d5a1a446b0bc1fbf0b2fce419b
c0a8d8cea32744cea47416c593526ac9
RY(theta₆)
858e55d5a1a446b0bc1fbf0b2fce419b--c0a8d8cea32744cea47416c593526ac9
dba1bb30426e4c4095dd4fcfb1f7ae34
RX(theta₁₀)
c0a8d8cea32744cea47416c593526ac9--dba1bb30426e4c4095dd4fcfb1f7ae34
d8d72ea272ab484a912441a947bc59b0
dba1bb30426e4c4095dd4fcfb1f7ae34--d8d72ea272ab484a912441a947bc59b0
09a8b1cf087d40debd7fca422b28e77e
X
d8d72ea272ab484a912441a947bc59b0--09a8b1cf087d40debd7fca422b28e77e
09a8b1cf087d40debd7fca422b28e77e--b88d4001c78942b8890e08d5e7aca18a
dbd9824b72db4535b31a682b3ce1dbc6
RX(theta₁₄)
09a8b1cf087d40debd7fca422b28e77e--dbd9824b72db4535b31a682b3ce1dbc6
0741a3129df84c83a35072c44ce20474
RY(theta₁₈)
dbd9824b72db4535b31a682b3ce1dbc6--0741a3129df84c83a35072c44ce20474
7c67fb0bf49c43d7b3c86ca5eb50dc52
RX(theta₂₂)
0741a3129df84c83a35072c44ce20474--7c67fb0bf49c43d7b3c86ca5eb50dc52
68e4b1a7155c4872ab8510cca7e48536
7c67fb0bf49c43d7b3c86ca5eb50dc52--68e4b1a7155c4872ab8510cca7e48536
14b4636e27c448af9e869ecd7cc80990
X
68e4b1a7155c4872ab8510cca7e48536--14b4636e27c448af9e869ecd7cc80990
14b4636e27c448af9e869ecd7cc80990--1f51b4b4993a4f9f9f75337814536573
14b4636e27c448af9e869ecd7cc80990--db03575d38f4462786ff4c843a69e245
24fa5775021a43b49b7340508bc19a71
d8d1f2293a2d4bc9a21bdd50276c9829
X
e316aba485864a01b4cdb79417dc36cf--d8d1f2293a2d4bc9a21bdd50276c9829
19d994c0bdad4ac8a00f305d8080a566
RX(theta₃)
d8d1f2293a2d4bc9a21bdd50276c9829--19d994c0bdad4ac8a00f305d8080a566
071744a6144c4e73be4606787107fc74
RY(theta₇)
19d994c0bdad4ac8a00f305d8080a566--071744a6144c4e73be4606787107fc74
aa40d011e7744173ad3430aa309ab606
RX(theta₁₁)
071744a6144c4e73be4606787107fc74--aa40d011e7744173ad3430aa309ab606
a9fbb69882c249efb63d3b3d5441f671
X
aa40d011e7744173ad3430aa309ab606--a9fbb69882c249efb63d3b3d5441f671
a9fbb69882c249efb63d3b3d5441f671--d8d72ea272ab484a912441a947bc59b0
b8469f5de45a4ff29f8e306e7b3e2b49
a9fbb69882c249efb63d3b3d5441f671--b8469f5de45a4ff29f8e306e7b3e2b49
5320789a2e4242e5812b391b6fb572f3
RX(theta₁₅)
b8469f5de45a4ff29f8e306e7b3e2b49--5320789a2e4242e5812b391b6fb572f3
04e013bdffe14458be7c27c9dde9ea82
RY(theta₁₉)
5320789a2e4242e5812b391b6fb572f3--04e013bdffe14458be7c27c9dde9ea82
d14ac4cc5ae34f44a56813f374d3bf2e
RX(theta₂₃)
04e013bdffe14458be7c27c9dde9ea82--d14ac4cc5ae34f44a56813f374d3bf2e
aafa2b924a1b448cb1da43863716e28e
X
d14ac4cc5ae34f44a56813f374d3bf2e--aafa2b924a1b448cb1da43863716e28e
aafa2b924a1b448cb1da43863716e28e--68e4b1a7155c4872ab8510cca7e48536
ebe205a6ffb04f349cfd81d11fae1b96
aafa2b924a1b448cb1da43863716e28e--ebe205a6ffb04f349cfd81d11fae1b96
ebe205a6ffb04f349cfd81d11fae1b96--24fa5775021a43b49b7340508bc19a71
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 , 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 , 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.1938-0.0520 j , -0.2004+0.3661 j , -0.0483-0.0577 j , -0.2657-0.3253 j ,
0.4508+0.0664 j , 0.2878+0.0577 j , -0.2979+0.1222 j , -0.0662+0.4491 j ],
[ 0.2315-0.2451 j , 0.2807+0.1053 j , -0.3644+0.4587 j , -0.0791+0.0530 j ,
-0.0125-0.1685 j , 0.2731-0.3878 j , -0.3455-0.2506 j , -0.0893-0.0241 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 )
├── 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 ]] )