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.30546026+0.95220482 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_ca715912287a497d9b4a3a96d601a089
Circuit block
cluster_70c9ed708aea4321ae3a2bd9fcdccfaf
Prep block
603649e250934cf9959fbde0519bd637
0
2ca63eef9a3c45c48a49636d080d6048
603649e250934cf9959fbde0519bd637--2ca63eef9a3c45c48a49636d080d6048
2b9846a63b254f8793c6d8711694cce0
1
ccd7fb41d9d4403d9b145b75a6266e65
RX(theta₀)
2ca63eef9a3c45c48a49636d080d6048--ccd7fb41d9d4403d9b145b75a6266e65
79e98a3dac1e457bb374af9accc0573c
RY(theta₄)
ccd7fb41d9d4403d9b145b75a6266e65--79e98a3dac1e457bb374af9accc0573c
942bb3e7d3b54d69b3c0aa38e8617773
RX(theta₈)
79e98a3dac1e457bb374af9accc0573c--942bb3e7d3b54d69b3c0aa38e8617773
14514fd0a0ec47ffbd0927a99dd366b2
942bb3e7d3b54d69b3c0aa38e8617773--14514fd0a0ec47ffbd0927a99dd366b2
a365c51c6e02447fac3bb2741953cd5a
14514fd0a0ec47ffbd0927a99dd366b2--a365c51c6e02447fac3bb2741953cd5a
61dab66ea9fe496398bc43b3e0b1013c
RX(theta₁₂)
a365c51c6e02447fac3bb2741953cd5a--61dab66ea9fe496398bc43b3e0b1013c
faa6573d657d43a1b267225089590144
RY(theta₁₆)
61dab66ea9fe496398bc43b3e0b1013c--faa6573d657d43a1b267225089590144
d2fa92bc44b74d36a8185c904f6d0b2d
RX(theta₂₀)
faa6573d657d43a1b267225089590144--d2fa92bc44b74d36a8185c904f6d0b2d
4a869df22ead435b99a8b7f39c44b8bd
d2fa92bc44b74d36a8185c904f6d0b2d--4a869df22ead435b99a8b7f39c44b8bd
c373f9ecbbaa479d87627969fb7c9ebd
4a869df22ead435b99a8b7f39c44b8bd--c373f9ecbbaa479d87627969fb7c9ebd
596f2e5448c0458e9269e5122485868d
c373f9ecbbaa479d87627969fb7c9ebd--596f2e5448c0458e9269e5122485868d
5489a4425bb94645be0ea2157eeaaf4f
97412dee97394e56a947d86137754d16
2b9846a63b254f8793c6d8711694cce0--97412dee97394e56a947d86137754d16
d446720b482d41b1bf93f829b064a87b
2
4edad9c5e93b4ad58a6602cfb4c92f78
RX(theta₁)
97412dee97394e56a947d86137754d16--4edad9c5e93b4ad58a6602cfb4c92f78
45dff26523254174974558ef0f45c191
RY(theta₅)
4edad9c5e93b4ad58a6602cfb4c92f78--45dff26523254174974558ef0f45c191
8b0112694080406aad0d7732830c6508
RX(theta₉)
45dff26523254174974558ef0f45c191--8b0112694080406aad0d7732830c6508
590f41c698a94398bb037c9690288763
X
8b0112694080406aad0d7732830c6508--590f41c698a94398bb037c9690288763
590f41c698a94398bb037c9690288763--14514fd0a0ec47ffbd0927a99dd366b2
acc6f59a60d048b587386c5b02782e13
590f41c698a94398bb037c9690288763--acc6f59a60d048b587386c5b02782e13
c6515de71350445dbbf1af5b9af14fc6
RX(theta₁₃)
acc6f59a60d048b587386c5b02782e13--c6515de71350445dbbf1af5b9af14fc6
1030a39da7f0458491f4923851bf01a9
RY(theta₁₇)
c6515de71350445dbbf1af5b9af14fc6--1030a39da7f0458491f4923851bf01a9
da15abeadc20448099ffd82dca8c5272
RX(theta₂₁)
1030a39da7f0458491f4923851bf01a9--da15abeadc20448099ffd82dca8c5272
86386e2d0c5943308638ef623d6e436b
X
da15abeadc20448099ffd82dca8c5272--86386e2d0c5943308638ef623d6e436b
86386e2d0c5943308638ef623d6e436b--4a869df22ead435b99a8b7f39c44b8bd
07a5fe53368e4818916816018cbbba40
86386e2d0c5943308638ef623d6e436b--07a5fe53368e4818916816018cbbba40
07a5fe53368e4818916816018cbbba40--5489a4425bb94645be0ea2157eeaaf4f
aa4f6b038719448c8d83c3cce0eb4bf2
c18dbab301a6429fb3503aa180ef7b31
d446720b482d41b1bf93f829b064a87b--c18dbab301a6429fb3503aa180ef7b31
d680d7b4a21642de90c45e4b7f68c2f0
3
3e54de857c29485b9ed3ac9689563176
RX(theta₂)
c18dbab301a6429fb3503aa180ef7b31--3e54de857c29485b9ed3ac9689563176
17a0d941cb8b4360a80c70736f512655
RY(theta₆)
3e54de857c29485b9ed3ac9689563176--17a0d941cb8b4360a80c70736f512655
613dfccbc7fd496c838d6d616e2ef5d0
RX(theta₁₀)
17a0d941cb8b4360a80c70736f512655--613dfccbc7fd496c838d6d616e2ef5d0
5e37f85f05514786ac482d6b447599a8
613dfccbc7fd496c838d6d616e2ef5d0--5e37f85f05514786ac482d6b447599a8
6536af51e02c4847ab6266e4e676f997
X
5e37f85f05514786ac482d6b447599a8--6536af51e02c4847ab6266e4e676f997
6536af51e02c4847ab6266e4e676f997--acc6f59a60d048b587386c5b02782e13
bb41b432c4d94477baa1d324020104e7
RX(theta₁₄)
6536af51e02c4847ab6266e4e676f997--bb41b432c4d94477baa1d324020104e7
279ff3a71c1c47ccae97291ac4d64cfd
RY(theta₁₈)
bb41b432c4d94477baa1d324020104e7--279ff3a71c1c47ccae97291ac4d64cfd
8d0c6defa73744b4b0d5d300d6261698
RX(theta₂₂)
279ff3a71c1c47ccae97291ac4d64cfd--8d0c6defa73744b4b0d5d300d6261698
cbbe45683af344a59d285c4a1a9c25c8
8d0c6defa73744b4b0d5d300d6261698--cbbe45683af344a59d285c4a1a9c25c8
c99dcdee95d9439f8f0719ad33124f10
X
cbbe45683af344a59d285c4a1a9c25c8--c99dcdee95d9439f8f0719ad33124f10
c99dcdee95d9439f8f0719ad33124f10--07a5fe53368e4818916816018cbbba40
c99dcdee95d9439f8f0719ad33124f10--aa4f6b038719448c8d83c3cce0eb4bf2
c2f307fd758a401ca46ee7929d054299
85e3263439884351a3d5f1980fb56f22
X
d680d7b4a21642de90c45e4b7f68c2f0--85e3263439884351a3d5f1980fb56f22
b78de9c8b9cc4b479f9d2cc3bdb8275f
RX(theta₃)
85e3263439884351a3d5f1980fb56f22--b78de9c8b9cc4b479f9d2cc3bdb8275f
f60874f81fad43aeb632a51c73f4438b
RY(theta₇)
b78de9c8b9cc4b479f9d2cc3bdb8275f--f60874f81fad43aeb632a51c73f4438b
afe1bb149f1d4e3aa35889ff1e9ad617
RX(theta₁₁)
f60874f81fad43aeb632a51c73f4438b--afe1bb149f1d4e3aa35889ff1e9ad617
87fcab68ae42436889b3f96e27ce53ff
X
afe1bb149f1d4e3aa35889ff1e9ad617--87fcab68ae42436889b3f96e27ce53ff
87fcab68ae42436889b3f96e27ce53ff--5e37f85f05514786ac482d6b447599a8
c9ccfaebb9144513a17197d361b94abf
87fcab68ae42436889b3f96e27ce53ff--c9ccfaebb9144513a17197d361b94abf
2aefb841902e4b1a9feda4d37d3acc31
RX(theta₁₅)
c9ccfaebb9144513a17197d361b94abf--2aefb841902e4b1a9feda4d37d3acc31
b1b24e71481b4b4192e5626925488899
RY(theta₁₉)
2aefb841902e4b1a9feda4d37d3acc31--b1b24e71481b4b4192e5626925488899
8cc67a51e27442b39f36c3e7d62b4847
RX(theta₂₃)
b1b24e71481b4b4192e5626925488899--8cc67a51e27442b39f36c3e7d62b4847
582b84050cfe4d029b97b79e9a7e4be4
X
8cc67a51e27442b39f36c3e7d62b4847--582b84050cfe4d029b97b79e9a7e4be4
582b84050cfe4d029b97b79e9a7e4be4--cbbe45683af344a59d285c4a1a9c25c8
deb8ec847c044be0a6041dfb9426c580
582b84050cfe4d029b97b79e9a7e4be4--deb8ec847c044be0a6041dfb9426c580
deb8ec847c044be0a6041dfb9426c580--c2f307fd758a401ca46ee7929d054299
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 , 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 , 1.+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.1144+0.3627 j , -0.2503+0.2489 j , -0.2721+0.0938 j , -0.4561-0.1925 j ,
0.0632-0.1867 j , 0.1342-0.4459 j , -0.2066+0.0367 j , -0.3065-0.0953 j ],
[ 0.3405-0.1517 j , -0.0806-0.2873 j , 0.2535+0.2733 j , 0.0322+0.0646 j ,
0.1300-0.0140 j , -0.0856-0.1621 j , -0.4057-0.4691 j , 0.2686+0.3471 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 )
└── 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 ]] )