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.30546026+0.95220482j 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_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)
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]])

Random 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, 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 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.1144+0.3627j, -0.2503+0.2489j, -0.2721+0.0938j, -0.4561-0.1925j,
          0.0632-0.1867j,  0.1342-0.4459j, -0.2066+0.0367j, -0.3065-0.0953j],
        [ 0.3405-0.1517j, -0.0806-0.2873j,  0.2535+0.2733j,  0.0322+0.0646j,
          0.1300-0.0140j, -0.0856-0.1621j, -0.4057-0.4691j,  0.2686+0.3471j]])

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)
├── X(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]])