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.90980227+0.41255036 j -0.01875312+0.04135647 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_319e0f06eeae4b52949d37bf659a66da
Circuit block
cluster_40f83db81ba34683bfa0f28e300d4c10
Prep block
99d8d3752a514b29827916a0bd953426
0
ffd16920480e4f6cbb4fdeafd6b50835
99d8d3752a514b29827916a0bd953426--ffd16920480e4f6cbb4fdeafd6b50835
d4ba2acdff794cb5bf55a1acbf1f3740
1
66f3fc9f9386473088295dbb6bdfc840
RX(theta₀)
ffd16920480e4f6cbb4fdeafd6b50835--66f3fc9f9386473088295dbb6bdfc840
1b823b85db794c4cb15a8da4de3ca1a4
RY(theta₄)
66f3fc9f9386473088295dbb6bdfc840--1b823b85db794c4cb15a8da4de3ca1a4
47fd2798d69f491f9d87eb1d3031f7b8
RX(theta₈)
1b823b85db794c4cb15a8da4de3ca1a4--47fd2798d69f491f9d87eb1d3031f7b8
f16ca87506774de2b8ad45123e98f0e9
47fd2798d69f491f9d87eb1d3031f7b8--f16ca87506774de2b8ad45123e98f0e9
b789cd8e7c394e62bd00a78c87e9e3d1
f16ca87506774de2b8ad45123e98f0e9--b789cd8e7c394e62bd00a78c87e9e3d1
bb360e6d577243b6b130995890e3b77a
RX(theta₁₂)
b789cd8e7c394e62bd00a78c87e9e3d1--bb360e6d577243b6b130995890e3b77a
10a4c62e3d07418392e13de9a8ec3040
RY(theta₁₆)
bb360e6d577243b6b130995890e3b77a--10a4c62e3d07418392e13de9a8ec3040
d8165703aef844018220700cde8c4254
RX(theta₂₀)
10a4c62e3d07418392e13de9a8ec3040--d8165703aef844018220700cde8c4254
0022c80b8ad44b5d988c9cb957d007fc
d8165703aef844018220700cde8c4254--0022c80b8ad44b5d988c9cb957d007fc
cea43c9152d94c9e8d2b32878ec9aed6
0022c80b8ad44b5d988c9cb957d007fc--cea43c9152d94c9e8d2b32878ec9aed6
28242d28cb8443adab5ed23c5badc79f
cea43c9152d94c9e8d2b32878ec9aed6--28242d28cb8443adab5ed23c5badc79f
b8ab4c116ce54f15a64233f96bf04ad6
44bd313d7dfb4dbf9d0de6ef0fd1eb33
d4ba2acdff794cb5bf55a1acbf1f3740--44bd313d7dfb4dbf9d0de6ef0fd1eb33
1879728bae0f495b8b7007e779685cc5
2
fd4b416daa9947719c16235799625612
RX(theta₁)
44bd313d7dfb4dbf9d0de6ef0fd1eb33--fd4b416daa9947719c16235799625612
1364a52156e749d59e9f8e53d979d657
RY(theta₅)
fd4b416daa9947719c16235799625612--1364a52156e749d59e9f8e53d979d657
e5117ca6ff7f4c209db20ef516cdf4f1
RX(theta₉)
1364a52156e749d59e9f8e53d979d657--e5117ca6ff7f4c209db20ef516cdf4f1
709773ef65124ae1b104db36048db709
X
e5117ca6ff7f4c209db20ef516cdf4f1--709773ef65124ae1b104db36048db709
709773ef65124ae1b104db36048db709--f16ca87506774de2b8ad45123e98f0e9
93d7aad433cd45a1bf3b4a63bdc6e5af
709773ef65124ae1b104db36048db709--93d7aad433cd45a1bf3b4a63bdc6e5af
d5595cae4f06429488b508127a4c2d09
RX(theta₁₃)
93d7aad433cd45a1bf3b4a63bdc6e5af--d5595cae4f06429488b508127a4c2d09
9dbdeb423c444686b51d0e2c08f25ff1
RY(theta₁₇)
d5595cae4f06429488b508127a4c2d09--9dbdeb423c444686b51d0e2c08f25ff1
90906089debc42648be33eb41abb5840
RX(theta₂₁)
9dbdeb423c444686b51d0e2c08f25ff1--90906089debc42648be33eb41abb5840
32de24098db74c2b997401c72db5e3ce
X
90906089debc42648be33eb41abb5840--32de24098db74c2b997401c72db5e3ce
32de24098db74c2b997401c72db5e3ce--0022c80b8ad44b5d988c9cb957d007fc
c11ef100bff5450792799c09c73d9417
32de24098db74c2b997401c72db5e3ce--c11ef100bff5450792799c09c73d9417
c11ef100bff5450792799c09c73d9417--b8ab4c116ce54f15a64233f96bf04ad6
3cea6e794f2a403cbebcaf9b448ec709
b57d6c60c94b4551bd6ffe397252d745
1879728bae0f495b8b7007e779685cc5--b57d6c60c94b4551bd6ffe397252d745
4afb61d4f51b4d56a7796952fc9578a3
3
83d8ae6221db4f528a49e655ee2a0e45
RX(theta₂)
b57d6c60c94b4551bd6ffe397252d745--83d8ae6221db4f528a49e655ee2a0e45
76239bd5cc024a2690b4b3a61d34adf2
RY(theta₆)
83d8ae6221db4f528a49e655ee2a0e45--76239bd5cc024a2690b4b3a61d34adf2
d970f4abf9414e58ac84a2303e136be1
RX(theta₁₀)
76239bd5cc024a2690b4b3a61d34adf2--d970f4abf9414e58ac84a2303e136be1
f222df8ce47b48b29a1f1b28f61ed662
d970f4abf9414e58ac84a2303e136be1--f222df8ce47b48b29a1f1b28f61ed662
bdb136e404ea44028160438d35b0e00b
X
f222df8ce47b48b29a1f1b28f61ed662--bdb136e404ea44028160438d35b0e00b
bdb136e404ea44028160438d35b0e00b--93d7aad433cd45a1bf3b4a63bdc6e5af
dfcbd11c12b74e68afa217f8f68a734e
RX(theta₁₄)
bdb136e404ea44028160438d35b0e00b--dfcbd11c12b74e68afa217f8f68a734e
2ca575f45cb24299af5e998ae58ed1a7
RY(theta₁₈)
dfcbd11c12b74e68afa217f8f68a734e--2ca575f45cb24299af5e998ae58ed1a7
e5a08dbc0e00429994bcae0e0e45ee79
RX(theta₂₂)
2ca575f45cb24299af5e998ae58ed1a7--e5a08dbc0e00429994bcae0e0e45ee79
cc5a11b084534bc7a086434b22ed424f
e5a08dbc0e00429994bcae0e0e45ee79--cc5a11b084534bc7a086434b22ed424f
d74032f13e5d4c4c9432ad52a4522563
X
cc5a11b084534bc7a086434b22ed424f--d74032f13e5d4c4c9432ad52a4522563
d74032f13e5d4c4c9432ad52a4522563--c11ef100bff5450792799c09c73d9417
d74032f13e5d4c4c9432ad52a4522563--3cea6e794f2a403cbebcaf9b448ec709
3b351ad30929473ba86bc830e9de58fb
29bcedbfb4c845e6b31f26aae4396843
X
4afb61d4f51b4d56a7796952fc9578a3--29bcedbfb4c845e6b31f26aae4396843
dbac4d04e8b94814ac40027ea324b19b
RX(theta₃)
29bcedbfb4c845e6b31f26aae4396843--dbac4d04e8b94814ac40027ea324b19b
cb3b068cdc0a44b09f3e9c48f1f77b41
RY(theta₇)
dbac4d04e8b94814ac40027ea324b19b--cb3b068cdc0a44b09f3e9c48f1f77b41
a040c173de6b4eea9df805ab8d1d55c3
RX(theta₁₁)
cb3b068cdc0a44b09f3e9c48f1f77b41--a040c173de6b4eea9df805ab8d1d55c3
ddf3b67564624471bd77c3e7df2905f0
X
a040c173de6b4eea9df805ab8d1d55c3--ddf3b67564624471bd77c3e7df2905f0
ddf3b67564624471bd77c3e7df2905f0--f222df8ce47b48b29a1f1b28f61ed662
ecfb1dfe67ac4c18a6f77eafc15ef3a9
ddf3b67564624471bd77c3e7df2905f0--ecfb1dfe67ac4c18a6f77eafc15ef3a9
f35dc61d95244440978542e517632bda
RX(theta₁₅)
ecfb1dfe67ac4c18a6f77eafc15ef3a9--f35dc61d95244440978542e517632bda
df1f7cc6f9b048389d2a8dedffab7469
RY(theta₁₉)
f35dc61d95244440978542e517632bda--df1f7cc6f9b048389d2a8dedffab7469
c6b4cd23ddd549398a261061c14e775b
RX(theta₂₃)
df1f7cc6f9b048389d2a8dedffab7469--c6b4cd23ddd549398a261061c14e775b
2014f80c1b5d41af883f84eba4e731f7
X
c6b4cd23ddd549398a261061c14e775b--2014f80c1b5d41af883f84eba4e731f7
2014f80c1b5d41af883f84eba4e731f7--cc5a11b084534bc7a086434b22ed424f
166720af94f04d93b16a77c0d112f65b
2014f80c1b5d41af883f84eba4e731f7--166720af94f04d93b16a77c0d112f65b
166720af94f04d93b16a77c0d112f65b--3b351ad30929473ba86bc830e9de58fb
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 , 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 , 0.+0. j , 0.+0. j , 1.+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.2361+0.3535 j , 0.3359+0.0865 j , -0.1484-0.0287 j , -0.2160+0.3155 j ,
0.1786-0.3860 j , 0.2846-0.2259 j , 0.2467-0.0175 j , -0.2484-0.3068 j ],
[ -0.1810+0.2598 j , -0.3196-0.1320 j , -0.1667-0.2685 j , -0.0097+0.0318 j ,
0.5178+0.0470 j , 0.2647-0.2489 j , -0.2764+0.3005 j , -0.0550-0.3274 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 )
└── 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 ]] )