Skip to content

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")
Random initial state generated with rotations:

state = [0.01809663-0.99983624j 0.        +0.j         0.        +0.j
 0.        +0.j        ]

Product state corresponding to bitstring '01':

state = [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_0a6b32fb99bb45c79da5aefd55f5b93e Circuit block cluster_b9ea93ae837045068d5b63cd7c6ac793 Prep block 3395f3e11b634dd6ae880c7e8ce821cd 0 d8c505d5762a45e7ac9d5b07d350d250 3395f3e11b634dd6ae880c7e8ce821cd--d8c505d5762a45e7ac9d5b07d350d250 b01be875bce64fdebb98c48465766b19 1 b192dcf6d9bf4ec19344509bb52726bb RX(theta₀) d8c505d5762a45e7ac9d5b07d350d250--b192dcf6d9bf4ec19344509bb52726bb e9388fceb3e74ef585803b47a76090ce RY(theta₄) b192dcf6d9bf4ec19344509bb52726bb--e9388fceb3e74ef585803b47a76090ce a183152b63e740db8e9bd0b9da0c99df RX(theta₈) e9388fceb3e74ef585803b47a76090ce--a183152b63e740db8e9bd0b9da0c99df 50aa66df7d214ee5adc06d31dc703a7f a183152b63e740db8e9bd0b9da0c99df--50aa66df7d214ee5adc06d31dc703a7f b46a4659b6aa44b7b6393050ef3ad8a7 50aa66df7d214ee5adc06d31dc703a7f--b46a4659b6aa44b7b6393050ef3ad8a7 3fb7a92dfd834ae0a342e870a4460432 RX(theta₁₂) b46a4659b6aa44b7b6393050ef3ad8a7--3fb7a92dfd834ae0a342e870a4460432 8e676596852242109be29f2282f2a24e RY(theta₁₆) 3fb7a92dfd834ae0a342e870a4460432--8e676596852242109be29f2282f2a24e 49f3749182c842f5bdac7507c044bb6a RX(theta₂₀) 8e676596852242109be29f2282f2a24e--49f3749182c842f5bdac7507c044bb6a 279827d0cf6d4e3394ff21a161ca963c 49f3749182c842f5bdac7507c044bb6a--279827d0cf6d4e3394ff21a161ca963c 315f4c4edfc14f7d80e15aedd2c99a98 279827d0cf6d4e3394ff21a161ca963c--315f4c4edfc14f7d80e15aedd2c99a98 8f1c38c85efe493aa343a887c09fd7b8 315f4c4edfc14f7d80e15aedd2c99a98--8f1c38c85efe493aa343a887c09fd7b8 2a4f3f880e8d444da77001145b26bdc3 3c1d533b1d7a4dada3c7de39ac6aaadc b01be875bce64fdebb98c48465766b19--3c1d533b1d7a4dada3c7de39ac6aaadc 3611ac2d67e241d2a0c53f2db7d1caf6 2 ae0a147f3eb74d2e865f38adb7e7ffa9 RX(theta₁) 3c1d533b1d7a4dada3c7de39ac6aaadc--ae0a147f3eb74d2e865f38adb7e7ffa9 b51b07f83d4944d595b8895a72f36bee RY(theta₅) ae0a147f3eb74d2e865f38adb7e7ffa9--b51b07f83d4944d595b8895a72f36bee 046cbbf4d632451f9d2166e20d0fc053 RX(theta₉) b51b07f83d4944d595b8895a72f36bee--046cbbf4d632451f9d2166e20d0fc053 2f619de87c4c4c65b92dec8b46af7fc8 X 046cbbf4d632451f9d2166e20d0fc053--2f619de87c4c4c65b92dec8b46af7fc8 2f619de87c4c4c65b92dec8b46af7fc8--50aa66df7d214ee5adc06d31dc703a7f bcf44f0223db4cb9a475fc48983d7b77 2f619de87c4c4c65b92dec8b46af7fc8--bcf44f0223db4cb9a475fc48983d7b77 5c99552e1c5740f698515f4cd98794d9 RX(theta₁₃) bcf44f0223db4cb9a475fc48983d7b77--5c99552e1c5740f698515f4cd98794d9 2c96bfdc1cca42088eccbb1d71cdaa8a RY(theta₁₇) 5c99552e1c5740f698515f4cd98794d9--2c96bfdc1cca42088eccbb1d71cdaa8a e8fafd4f1d654006aa15c404075eaab2 RX(theta₂₁) 2c96bfdc1cca42088eccbb1d71cdaa8a--e8fafd4f1d654006aa15c404075eaab2 8634cb80c97f4c99b0d5fce47bbb599d X e8fafd4f1d654006aa15c404075eaab2--8634cb80c97f4c99b0d5fce47bbb599d 8634cb80c97f4c99b0d5fce47bbb599d--279827d0cf6d4e3394ff21a161ca963c 5f87f084820e470791459c3c70a17de8 8634cb80c97f4c99b0d5fce47bbb599d--5f87f084820e470791459c3c70a17de8 5f87f084820e470791459c3c70a17de8--2a4f3f880e8d444da77001145b26bdc3 63c9bdfc81bc4680a20655deb8817f7f 6905ff0dea0c47578ffdcf6a2393cd4b 3611ac2d67e241d2a0c53f2db7d1caf6--6905ff0dea0c47578ffdcf6a2393cd4b 7e4646f2ba444fd98f6bdbff6b82ea10 3 67f47cf0cbb34e42968662f8e94638ce RX(theta₂) 6905ff0dea0c47578ffdcf6a2393cd4b--67f47cf0cbb34e42968662f8e94638ce eaf1e1c4367144bcaa764d4b2951a4b0 RY(theta₆) 67f47cf0cbb34e42968662f8e94638ce--eaf1e1c4367144bcaa764d4b2951a4b0 aa6f3329433146c7aa2c41543a70010f RX(theta₁₀) eaf1e1c4367144bcaa764d4b2951a4b0--aa6f3329433146c7aa2c41543a70010f 64d74eb36be54f4e8db1a6a575f772a4 aa6f3329433146c7aa2c41543a70010f--64d74eb36be54f4e8db1a6a575f772a4 ccc84665bd0240749e16ecb6eaa58455 X 64d74eb36be54f4e8db1a6a575f772a4--ccc84665bd0240749e16ecb6eaa58455 ccc84665bd0240749e16ecb6eaa58455--bcf44f0223db4cb9a475fc48983d7b77 eb0d50aaee464199987a8a614ba8383b RX(theta₁₄) ccc84665bd0240749e16ecb6eaa58455--eb0d50aaee464199987a8a614ba8383b 4b5e9cecbdb64f6b833691c5d6f1f8d6 RY(theta₁₈) eb0d50aaee464199987a8a614ba8383b--4b5e9cecbdb64f6b833691c5d6f1f8d6 e65768df075e40bda8e861756a5037e4 RX(theta₂₂) 4b5e9cecbdb64f6b833691c5d6f1f8d6--e65768df075e40bda8e861756a5037e4 870c2674b06d4648ab85364ff8d1b6de e65768df075e40bda8e861756a5037e4--870c2674b06d4648ab85364ff8d1b6de def1f895eabf470ca0902b7ad8860fe5 X 870c2674b06d4648ab85364ff8d1b6de--def1f895eabf470ca0902b7ad8860fe5 def1f895eabf470ca0902b7ad8860fe5--5f87f084820e470791459c3c70a17de8 def1f895eabf470ca0902b7ad8860fe5--63c9bdfc81bc4680a20655deb8817f7f 77c15032d8924f9884c2c28b39de4b97 514bf6d5bc2f4322ac831a0991c3c24f X 7e4646f2ba444fd98f6bdbff6b82ea10--514bf6d5bc2f4322ac831a0991c3c24f bff7b7daf9324c7db9af31ee2bdf3070 RX(theta₃) 514bf6d5bc2f4322ac831a0991c3c24f--bff7b7daf9324c7db9af31ee2bdf3070 3ec864544e1043d19da9c98308127315 RY(theta₇) bff7b7daf9324c7db9af31ee2bdf3070--3ec864544e1043d19da9c98308127315 9e6f78f2dc0244419317777e3153db86 RX(theta₁₁) 3ec864544e1043d19da9c98308127315--9e6f78f2dc0244419317777e3153db86 798779952d074ce08425946b88f23944 X 9e6f78f2dc0244419317777e3153db86--798779952d074ce08425946b88f23944 798779952d074ce08425946b88f23944--64d74eb36be54f4e8db1a6a575f772a4 7bd1283132834a319b25dd2ed83fe358 798779952d074ce08425946b88f23944--7bd1283132834a319b25dd2ed83fe358 84fc4f7fb71c405a987e8df99a0f7f16 RX(theta₁₅) 7bd1283132834a319b25dd2ed83fe358--84fc4f7fb71c405a987e8df99a0f7f16 a5ae50fc756f4c1a9a7a62e9df4701a5 RY(theta₁₉) 84fc4f7fb71c405a987e8df99a0f7f16--a5ae50fc756f4c1a9a7a62e9df4701a5 b252f48bc10847b28ca4d96f05452d82 RX(theta₂₃) a5ae50fc756f4c1a9a7a62e9df4701a5--b252f48bc10847b28ca4d96f05452d82 ea214093524b42c994aeb2ab39301901 X b252f48bc10847b28ca4d96f05452d82--ea214093524b42c994aeb2ab39301901 ea214093524b42c994aeb2ab39301901--870c2674b06d4648ab85364ff8d1b6de a4ca911d234847cb85dd724fa386d8ef ea214093524b42c994aeb2ab39301901--a4ca911d234847cb85dd724fa386d8ef a4ca911d234847cb85dd724fa386d8ef--77c15032d8924f9884c2c28b39de4b97
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)
Uniform state = 

tensor([[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 state = 

tensor([[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]])
One state = 

tensor([[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)
Product state = 

tensor([[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]])

Random state = 

tensor([[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, 1.+0.j, 0.+0.j, 0.+0.j, 0.+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 state = 

tensor([[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)
Random state from Haar = 

tensor([[ 0.2561-0.1032j,  0.0494+0.0587j,  0.3258+0.1880j,  0.2518-0.0606j,
         -0.3047-0.3365j, -0.0829+0.4560j,  0.2562+0.1226j, -0.1817+0.4180j],
        [ 0.3139+0.4935j, -0.2357+0.3002j,  0.4257+0.0696j,  0.0326+0.0448j,
          0.1226-0.1125j, -0.2873+0.1443j, -0.1797-0.3972j, -0.0041-0.0452j]])

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)
Final state = tensor([[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)
KronBlock(0,1,2)
├── H(0)
├── H(1)
└── H(2)
KronBlock(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)
KronBlock(0,1,2)
├── X(0)
├── I(1)
└── I(2)
KronBlock(0,1,2)
├── I(0)
├── I(1)
└── I(2)

And GHZ states:

from qadence import ghz_block

ghz_block = ghz_block(n_qubits)
ChainBlock(0,1,2)
├── H(0)
└── ChainBlock(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)
Categorical(probs: torch.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))
True

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))
tensor([[0.5000+0.j, 0.5000+0.j, 0.5000+0.j, 0.5000+0.j]])