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.98111062+0. j 0.08438519+0. j 0. + 0.17343176 j
0. + 0.01491684 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_afaef9aac5de4cc5b28f43cb537ce0cc
Circuit block
cluster_75bcf2f28e6a41d1abfc0ab2ebfd0adc
Prep block
cfad5fcadc294a5c890ff2de256f7eef
0
2bc5769d554b4963a829848c804bbd85
cfad5fcadc294a5c890ff2de256f7eef--2bc5769d554b4963a829848c804bbd85
d43f06ebf6b049c4ac2b2e14ef66d48b
1
54fff406b4274ca4bbe0f11e6dfe7e48
RX(theta₀)
2bc5769d554b4963a829848c804bbd85--54fff406b4274ca4bbe0f11e6dfe7e48
83e4947cc3954b739bd4b5dba6b379c5
RY(theta₄)
54fff406b4274ca4bbe0f11e6dfe7e48--83e4947cc3954b739bd4b5dba6b379c5
52ed7b2424f64432be239e07cce81066
RX(theta₈)
83e4947cc3954b739bd4b5dba6b379c5--52ed7b2424f64432be239e07cce81066
9b427bd5148a4f579f874a006a2ed453
52ed7b2424f64432be239e07cce81066--9b427bd5148a4f579f874a006a2ed453
bb6476075c9545e6b1c225d8ff48e0d3
9b427bd5148a4f579f874a006a2ed453--bb6476075c9545e6b1c225d8ff48e0d3
454d41f70d2b4b06b880d405ee57ba5a
RX(theta₁₂)
bb6476075c9545e6b1c225d8ff48e0d3--454d41f70d2b4b06b880d405ee57ba5a
c82c8b8824264114a26d5a6d2326fd22
RY(theta₁₆)
454d41f70d2b4b06b880d405ee57ba5a--c82c8b8824264114a26d5a6d2326fd22
7d19e6cc1dad476cb53c13888a953db5
RX(theta₂₀)
c82c8b8824264114a26d5a6d2326fd22--7d19e6cc1dad476cb53c13888a953db5
2b91091e2a924e4ba8d916cbde4596b2
7d19e6cc1dad476cb53c13888a953db5--2b91091e2a924e4ba8d916cbde4596b2
ce02a40c557a41d18abc02da38041c31
2b91091e2a924e4ba8d916cbde4596b2--ce02a40c557a41d18abc02da38041c31
8539094df6174952a186767e778f1c91
ce02a40c557a41d18abc02da38041c31--8539094df6174952a186767e778f1c91
b4aebab4f9a44fa5aae1c08bafe99ef5
7765ad7bc2114068ab64613d74902cda
d43f06ebf6b049c4ac2b2e14ef66d48b--7765ad7bc2114068ab64613d74902cda
907df7c4ea3547f78f204e516c22cda0
2
8b755f8a1b704915aff6aa8088013de1
RX(theta₁)
7765ad7bc2114068ab64613d74902cda--8b755f8a1b704915aff6aa8088013de1
97d10a74a4c840109b8a7fd403564bb9
RY(theta₅)
8b755f8a1b704915aff6aa8088013de1--97d10a74a4c840109b8a7fd403564bb9
9ada60d8e1ec4e7ea97d0ed67e40f5c9
RX(theta₉)
97d10a74a4c840109b8a7fd403564bb9--9ada60d8e1ec4e7ea97d0ed67e40f5c9
fcfa538221c346299717d2742f5632ed
X
9ada60d8e1ec4e7ea97d0ed67e40f5c9--fcfa538221c346299717d2742f5632ed
fcfa538221c346299717d2742f5632ed--9b427bd5148a4f579f874a006a2ed453
57413f60c0864f418782741097a1a3dd
fcfa538221c346299717d2742f5632ed--57413f60c0864f418782741097a1a3dd
41d4946cfe174e81a934b3abd5450ebb
RX(theta₁₃)
57413f60c0864f418782741097a1a3dd--41d4946cfe174e81a934b3abd5450ebb
1f819e87fdcf4d9eb0e29195ff5f73fe
RY(theta₁₇)
41d4946cfe174e81a934b3abd5450ebb--1f819e87fdcf4d9eb0e29195ff5f73fe
ec60ad5c75724f139543aea16383adcb
RX(theta₂₁)
1f819e87fdcf4d9eb0e29195ff5f73fe--ec60ad5c75724f139543aea16383adcb
e72acb5afc6f4b5b9117d9894ac27989
X
ec60ad5c75724f139543aea16383adcb--e72acb5afc6f4b5b9117d9894ac27989
e72acb5afc6f4b5b9117d9894ac27989--2b91091e2a924e4ba8d916cbde4596b2
a970e1c4db864d09b58102d9df7e8fa5
e72acb5afc6f4b5b9117d9894ac27989--a970e1c4db864d09b58102d9df7e8fa5
a970e1c4db864d09b58102d9df7e8fa5--b4aebab4f9a44fa5aae1c08bafe99ef5
e70687a548bc4faaab8897e82682bee3
8c522278d23f45efb428a6a9b00968ce
907df7c4ea3547f78f204e516c22cda0--8c522278d23f45efb428a6a9b00968ce
85b9718d33194a7a9e74fae708e2c229
3
83f5932bce594b4cbb6a5ead5c31a3d1
RX(theta₂)
8c522278d23f45efb428a6a9b00968ce--83f5932bce594b4cbb6a5ead5c31a3d1
e6101c174949414a87094a7a38575b9a
RY(theta₆)
83f5932bce594b4cbb6a5ead5c31a3d1--e6101c174949414a87094a7a38575b9a
d001bb58e8614be3801a963965b48ee9
RX(theta₁₀)
e6101c174949414a87094a7a38575b9a--d001bb58e8614be3801a963965b48ee9
4aefbb1e1d624edd97a42d19bac4ec88
d001bb58e8614be3801a963965b48ee9--4aefbb1e1d624edd97a42d19bac4ec88
22bd7641cab74cb5884026db2f3c17a6
X
4aefbb1e1d624edd97a42d19bac4ec88--22bd7641cab74cb5884026db2f3c17a6
22bd7641cab74cb5884026db2f3c17a6--57413f60c0864f418782741097a1a3dd
0b50d19ff84747a7a5eeac3e9086b804
RX(theta₁₄)
22bd7641cab74cb5884026db2f3c17a6--0b50d19ff84747a7a5eeac3e9086b804
b1df69d88c10455494a953c417c77b78
RY(theta₁₈)
0b50d19ff84747a7a5eeac3e9086b804--b1df69d88c10455494a953c417c77b78
17eae20d08e246358a51d3dfc964c995
RX(theta₂₂)
b1df69d88c10455494a953c417c77b78--17eae20d08e246358a51d3dfc964c995
7f8ad99c7cc549bd948e872ab03dc6bf
17eae20d08e246358a51d3dfc964c995--7f8ad99c7cc549bd948e872ab03dc6bf
b03d061883c44d1483b3622d0ce502f2
X
7f8ad99c7cc549bd948e872ab03dc6bf--b03d061883c44d1483b3622d0ce502f2
b03d061883c44d1483b3622d0ce502f2--a970e1c4db864d09b58102d9df7e8fa5
b03d061883c44d1483b3622d0ce502f2--e70687a548bc4faaab8897e82682bee3
c9b4a546fa8e44d1a7ff9427c2064173
322ec9ed6d284054b385636ec2623dd7
X
85b9718d33194a7a9e74fae708e2c229--322ec9ed6d284054b385636ec2623dd7
b89f62b3054648938818e1e832df73cb
RX(theta₃)
322ec9ed6d284054b385636ec2623dd7--b89f62b3054648938818e1e832df73cb
777f755e02c84a048b43943c6368ef53
RY(theta₇)
b89f62b3054648938818e1e832df73cb--777f755e02c84a048b43943c6368ef53
11be39d03b104af3a0bdc47fb3af7056
RX(theta₁₁)
777f755e02c84a048b43943c6368ef53--11be39d03b104af3a0bdc47fb3af7056
1a16ccc8f7b949aea3408b2021e6bc82
X
11be39d03b104af3a0bdc47fb3af7056--1a16ccc8f7b949aea3408b2021e6bc82
1a16ccc8f7b949aea3408b2021e6bc82--4aefbb1e1d624edd97a42d19bac4ec88
cc4c60bbb09b4d1f86dffeed87830200
1a16ccc8f7b949aea3408b2021e6bc82--cc4c60bbb09b4d1f86dffeed87830200
54a85eb1543442bba175957a354b35d6
RX(theta₁₅)
cc4c60bbb09b4d1f86dffeed87830200--54a85eb1543442bba175957a354b35d6
bec423b730e04a26a33ed60e3a4b56c0
RY(theta₁₉)
54a85eb1543442bba175957a354b35d6--bec423b730e04a26a33ed60e3a4b56c0
f2b813e60e59486f9bb8d0b15ec3d7d3
RX(theta₂₃)
bec423b730e04a26a33ed60e3a4b56c0--f2b813e60e59486f9bb8d0b15ec3d7d3
5ee1854df468423ca7b3a95ef4bf0599
X
f2b813e60e59486f9bb8d0b15ec3d7d3--5ee1854df468423ca7b3a95ef4bf0599
5ee1854df468423ca7b3a95ef4bf0599--7f8ad99c7cc549bd948e872ab03dc6bf
208dfcb3ebbc4da5abf311a1526721e7
5ee1854df468423ca7b3a95ef4bf0599--208dfcb3ebbc4da5abf311a1526721e7
208dfcb3ebbc4da5abf311a1526721e7--c9b4a546fa8e44d1a7ff9427c2064173
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 , 0.+0. j , 1.+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.1732-0.0990 j , 0.2022+0.2079 j , -0.1102+0.2475 j , -0.2171+0.4750 j ,
0.1075-0.0152 j , -0.0820+0.1841 j , -0.1133-0.1981 j , -0.6522-0.0096 j ],
[ -0.0571+0.1382 j , -0.6252+0.0486 j , 0.2354-0.4191 j , -0.0668+0.0385 j ,
0.0395-0.1282 j , 0.1214-0.4909 j , 0.0412+0.0087 j , 0.2465-0.1057 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 )
└── 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 ]] )