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.89790539+0.j -0.17791877+0.j -0.39495107+0.j  0.07825903+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_1101a68aa26e49218030e0127d8c1a04 Circuit block cluster_d63fc83829e640619e0dbd2b3f35d212 Prep block 6d2b9440f791492eb7b8233e0243bd98 0 74826676cd06473d8c1e37191135b948 6d2b9440f791492eb7b8233e0243bd98--74826676cd06473d8c1e37191135b948 1ada91a624c348488165841be79f48c3 1 4cb5842f52a4492c9db4a8d181541ce0 RX(theta₀) 74826676cd06473d8c1e37191135b948--4cb5842f52a4492c9db4a8d181541ce0 f83c55e2b9fd41339c722e6693c3ade8 RY(theta₄) 4cb5842f52a4492c9db4a8d181541ce0--f83c55e2b9fd41339c722e6693c3ade8 4f58b67aae284bb49f101ed7e94cc866 RX(theta₈) f83c55e2b9fd41339c722e6693c3ade8--4f58b67aae284bb49f101ed7e94cc866 c009d6fb222e4fe98768cc839a25b96e 4f58b67aae284bb49f101ed7e94cc866--c009d6fb222e4fe98768cc839a25b96e e01fb2ae970e4beabac715f7332dd3a6 c009d6fb222e4fe98768cc839a25b96e--e01fb2ae970e4beabac715f7332dd3a6 98c1ae999a73463eb938d15c19a32863 RX(theta₁₂) e01fb2ae970e4beabac715f7332dd3a6--98c1ae999a73463eb938d15c19a32863 378f0c1c97f944f7881152acfc07a08e RY(theta₁₆) 98c1ae999a73463eb938d15c19a32863--378f0c1c97f944f7881152acfc07a08e 755a9a8b37c44d02b9beb29b1808cf68 RX(theta₂₀) 378f0c1c97f944f7881152acfc07a08e--755a9a8b37c44d02b9beb29b1808cf68 4f247b7b76444a8b846976e43340a1ab 755a9a8b37c44d02b9beb29b1808cf68--4f247b7b76444a8b846976e43340a1ab d9018a4078e14eed95db3b928f53c6dc 4f247b7b76444a8b846976e43340a1ab--d9018a4078e14eed95db3b928f53c6dc c1ccb02974064ba1bad4c6e27d197f9b d9018a4078e14eed95db3b928f53c6dc--c1ccb02974064ba1bad4c6e27d197f9b 3a3911a030c94be8b210f4c8755c0ea8 7ea42b763000499b9dbd19a69322b6b7 1ada91a624c348488165841be79f48c3--7ea42b763000499b9dbd19a69322b6b7 96456103357f478aac935d2b8fc17c67 2 fb9324a7b0724ea884cdeff6a9c46941 RX(theta₁) 7ea42b763000499b9dbd19a69322b6b7--fb9324a7b0724ea884cdeff6a9c46941 bc98407a0d4e4fbe892ecf092a36697f RY(theta₅) fb9324a7b0724ea884cdeff6a9c46941--bc98407a0d4e4fbe892ecf092a36697f f1abe42231d6471da92bbe3f640a9017 RX(theta₉) bc98407a0d4e4fbe892ecf092a36697f--f1abe42231d6471da92bbe3f640a9017 c11073b507d648e3bb5ec40579162607 X f1abe42231d6471da92bbe3f640a9017--c11073b507d648e3bb5ec40579162607 c11073b507d648e3bb5ec40579162607--c009d6fb222e4fe98768cc839a25b96e aa3a681f50ba476b802493b3924412c5 c11073b507d648e3bb5ec40579162607--aa3a681f50ba476b802493b3924412c5 8554480d30da439093c003079bc51d67 RX(theta₁₃) aa3a681f50ba476b802493b3924412c5--8554480d30da439093c003079bc51d67 686e107ca9b14f48ab5731cfdd08688d RY(theta₁₇) 8554480d30da439093c003079bc51d67--686e107ca9b14f48ab5731cfdd08688d c86fb31129cc4629a9d3025f7c139065 RX(theta₂₁) 686e107ca9b14f48ab5731cfdd08688d--c86fb31129cc4629a9d3025f7c139065 57419287744e429a9b942e5dd72fe6b8 X c86fb31129cc4629a9d3025f7c139065--57419287744e429a9b942e5dd72fe6b8 57419287744e429a9b942e5dd72fe6b8--4f247b7b76444a8b846976e43340a1ab d70859a97c1b4e41880e0c099bc13e72 57419287744e429a9b942e5dd72fe6b8--d70859a97c1b4e41880e0c099bc13e72 d70859a97c1b4e41880e0c099bc13e72--3a3911a030c94be8b210f4c8755c0ea8 6ecb4e38b3a6482594aee5699879fd26 67dfe4fc214a462dbb2a7a0eb8252343 96456103357f478aac935d2b8fc17c67--67dfe4fc214a462dbb2a7a0eb8252343 f4a09b49edbe482e8e478595f23bb955 3 bedb01118a7843c5b40f14b89c471f19 RX(theta₂) 67dfe4fc214a462dbb2a7a0eb8252343--bedb01118a7843c5b40f14b89c471f19 d83f83393e4a4905bbfba73d66716ea9 RY(theta₆) bedb01118a7843c5b40f14b89c471f19--d83f83393e4a4905bbfba73d66716ea9 6450e41079754d3f931ee39df30d5b02 RX(theta₁₀) d83f83393e4a4905bbfba73d66716ea9--6450e41079754d3f931ee39df30d5b02 5667e93558b64cec89e30ab4ae9076be 6450e41079754d3f931ee39df30d5b02--5667e93558b64cec89e30ab4ae9076be 288ee51c326f421085beb29b111bef96 X 5667e93558b64cec89e30ab4ae9076be--288ee51c326f421085beb29b111bef96 288ee51c326f421085beb29b111bef96--aa3a681f50ba476b802493b3924412c5 b1ea7d9351304dafa27f37bbce0fc2ce RX(theta₁₄) 288ee51c326f421085beb29b111bef96--b1ea7d9351304dafa27f37bbce0fc2ce 0bfa32c0a4ba48a890a36518c6dbdf6e RY(theta₁₈) b1ea7d9351304dafa27f37bbce0fc2ce--0bfa32c0a4ba48a890a36518c6dbdf6e 34bb754d1ac0430da7afce3db5580565 RX(theta₂₂) 0bfa32c0a4ba48a890a36518c6dbdf6e--34bb754d1ac0430da7afce3db5580565 09f142b8a44544748b1c5ddeaac0ccdf 34bb754d1ac0430da7afce3db5580565--09f142b8a44544748b1c5ddeaac0ccdf 41c658cf929d4c7d839d46453ca323de X 09f142b8a44544748b1c5ddeaac0ccdf--41c658cf929d4c7d839d46453ca323de 41c658cf929d4c7d839d46453ca323de--d70859a97c1b4e41880e0c099bc13e72 41c658cf929d4c7d839d46453ca323de--6ecb4e38b3a6482594aee5699879fd26 269c0806b7eb480990bd4a881bb3c59d 8b3471fff2524dd68ea18e0d2c7f24da X f4a09b49edbe482e8e478595f23bb955--8b3471fff2524dd68ea18e0d2c7f24da 4c13db85fd7f461ab7f2fab1ca60b884 RX(theta₃) 8b3471fff2524dd68ea18e0d2c7f24da--4c13db85fd7f461ab7f2fab1ca60b884 b164931a9f5c4f2fb66eaac8a8c1ec0a RY(theta₇) 4c13db85fd7f461ab7f2fab1ca60b884--b164931a9f5c4f2fb66eaac8a8c1ec0a 6b3540d6aebe4c4fa0494fae14cb90a5 RX(theta₁₁) b164931a9f5c4f2fb66eaac8a8c1ec0a--6b3540d6aebe4c4fa0494fae14cb90a5 7364b3b6ce84404592731800b3dd0b81 X 6b3540d6aebe4c4fa0494fae14cb90a5--7364b3b6ce84404592731800b3dd0b81 7364b3b6ce84404592731800b3dd0b81--5667e93558b64cec89e30ab4ae9076be e367fe2e83c744a3a302cf7795bece78 7364b3b6ce84404592731800b3dd0b81--e367fe2e83c744a3a302cf7795bece78 e46fe8323e594880a9436e7a8cde5731 RX(theta₁₅) e367fe2e83c744a3a302cf7795bece78--e46fe8323e594880a9436e7a8cde5731 9fe63edf792745e5ae77ab9cd8ff7f11 RY(theta₁₉) e46fe8323e594880a9436e7a8cde5731--9fe63edf792745e5ae77ab9cd8ff7f11 c239a81f16bd47939e65c6ca7959ab70 RX(theta₂₃) 9fe63edf792745e5ae77ab9cd8ff7f11--c239a81f16bd47939e65c6ca7959ab70 8cf95ced097b4085beb3dea8245f36ed X c239a81f16bd47939e65c6ca7959ab70--8cf95ced097b4085beb3dea8245f36ed 8cf95ced097b4085beb3dea8245f36ed--09f142b8a44544748b1c5ddeaac0ccdf c149365aabd74be282c9bd718991718b 8cf95ced097b4085beb3dea8245f36ed--c149365aabd74be282c9bd718991718b c149365aabd74be282c9bd718991718b--269c0806b7eb480990bd4a881bb3c59d
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, 0.+0.j, 0.+0.j, 1.+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]])

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.0960-0.0362j, -0.1035+0.1122j,  0.0139+0.2543j,  0.2133+0.1648j,
          0.4687+0.2195j, -0.2819+0.0705j, -0.0940-0.0842j,  0.5079-0.4499j],
        [ 0.0447-0.2164j, -0.1827-0.2467j, -0.1432+0.0792j, -0.2743-0.1482j,
         -0.0855+0.2340j,  0.1316+0.4042j,  0.0874-0.5930j,  0.3484-0.0977j]])

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