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.78316776+0.38817527j  0.        +0.j         -0.21572422+0.43523705j
  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_991d5031cc494a90aa06fab91316e892 Circuit block cluster_d30861260a9c43f188db28d9e340e41b Prep block d969d29724c74b5db045841114fd6b74 0 f092b17165bb43d99c811bb59ed38cf4 d969d29724c74b5db045841114fd6b74--f092b17165bb43d99c811bb59ed38cf4 d561fb67aa344c6eadcd6c336c3174d4 1 382642cee59047309df7ef47766c95c9 RX(theta₀) f092b17165bb43d99c811bb59ed38cf4--382642cee59047309df7ef47766c95c9 71e0ec1123414b098cc569215af2346a RY(theta₄) 382642cee59047309df7ef47766c95c9--71e0ec1123414b098cc569215af2346a d219f16b5eac4ee488611232573a8aac RX(theta₈) 71e0ec1123414b098cc569215af2346a--d219f16b5eac4ee488611232573a8aac 647c15b00fae401f94c50d08108d1f75 d219f16b5eac4ee488611232573a8aac--647c15b00fae401f94c50d08108d1f75 70208c4e5e60420684c042a5a866ac56 647c15b00fae401f94c50d08108d1f75--70208c4e5e60420684c042a5a866ac56 86542da964454a198676ad8e337329f2 RX(theta₁₂) 70208c4e5e60420684c042a5a866ac56--86542da964454a198676ad8e337329f2 f734bfac41744c4ea6318f2877a7b19a RY(theta₁₆) 86542da964454a198676ad8e337329f2--f734bfac41744c4ea6318f2877a7b19a fdf8d60052e34cc396a8519dd2e10078 RX(theta₂₀) f734bfac41744c4ea6318f2877a7b19a--fdf8d60052e34cc396a8519dd2e10078 fb71f0458b534acc8bd3ad4ab0f9e760 fdf8d60052e34cc396a8519dd2e10078--fb71f0458b534acc8bd3ad4ab0f9e760 beb8e2c0898e41fca00433887f37b888 fb71f0458b534acc8bd3ad4ab0f9e760--beb8e2c0898e41fca00433887f37b888 bf28bbffe3544402a5a91b49d2486c2c beb8e2c0898e41fca00433887f37b888--bf28bbffe3544402a5a91b49d2486c2c 89562545eb7f433fb23978ffbb272891 34d0edef382049a39093e286b32f450b d561fb67aa344c6eadcd6c336c3174d4--34d0edef382049a39093e286b32f450b b7c5da04d8354f49ad7e77362fc6406b 2 6af6cdd0eeea4823a6185d0ef0f8914e RX(theta₁) 34d0edef382049a39093e286b32f450b--6af6cdd0eeea4823a6185d0ef0f8914e 6b79320afc334956ad4f2bbd7473770f RY(theta₅) 6af6cdd0eeea4823a6185d0ef0f8914e--6b79320afc334956ad4f2bbd7473770f 2d177ca021ac4a52b3deaf3ef132d56e RX(theta₉) 6b79320afc334956ad4f2bbd7473770f--2d177ca021ac4a52b3deaf3ef132d56e 24854a90bb424c40b69563861761ff0d X 2d177ca021ac4a52b3deaf3ef132d56e--24854a90bb424c40b69563861761ff0d 24854a90bb424c40b69563861761ff0d--647c15b00fae401f94c50d08108d1f75 560bebf06e3e46e4a742a85a00e0ce2c 24854a90bb424c40b69563861761ff0d--560bebf06e3e46e4a742a85a00e0ce2c 044a592b183c47068438b20da2ecfa51 RX(theta₁₃) 560bebf06e3e46e4a742a85a00e0ce2c--044a592b183c47068438b20da2ecfa51 a5a1065ee16c469fb2a1cd3da7ae9c8c RY(theta₁₇) 044a592b183c47068438b20da2ecfa51--a5a1065ee16c469fb2a1cd3da7ae9c8c ca5aceb906a2417d8e5bb9bd0c7f5d4d RX(theta₂₁) a5a1065ee16c469fb2a1cd3da7ae9c8c--ca5aceb906a2417d8e5bb9bd0c7f5d4d c689e64aacfb466488a196dcc19f4ae9 X ca5aceb906a2417d8e5bb9bd0c7f5d4d--c689e64aacfb466488a196dcc19f4ae9 c689e64aacfb466488a196dcc19f4ae9--fb71f0458b534acc8bd3ad4ab0f9e760 f04907cf8a894431ac373af0248c1f9f c689e64aacfb466488a196dcc19f4ae9--f04907cf8a894431ac373af0248c1f9f f04907cf8a894431ac373af0248c1f9f--89562545eb7f433fb23978ffbb272891 73dfb1e0c00141fd84125346442e7e0a e4940a1468bd4db1aa7a18f2c716fc27 b7c5da04d8354f49ad7e77362fc6406b--e4940a1468bd4db1aa7a18f2c716fc27 5f74b65f3e8f49e9bfc8b8d4e8791ba1 3 13f9a9d57d2c4de2bfd5309d284e8394 RX(theta₂) e4940a1468bd4db1aa7a18f2c716fc27--13f9a9d57d2c4de2bfd5309d284e8394 ae893ed2329d4304b3586e60fa32d9e3 RY(theta₆) 13f9a9d57d2c4de2bfd5309d284e8394--ae893ed2329d4304b3586e60fa32d9e3 390dcf8752fb4c13a9b64ba1103e73a6 RX(theta₁₀) ae893ed2329d4304b3586e60fa32d9e3--390dcf8752fb4c13a9b64ba1103e73a6 ba4d6eca83814ad7a56f8b94d880d7fb 390dcf8752fb4c13a9b64ba1103e73a6--ba4d6eca83814ad7a56f8b94d880d7fb 1dea952910a6403888a5ffab11444b82 X ba4d6eca83814ad7a56f8b94d880d7fb--1dea952910a6403888a5ffab11444b82 1dea952910a6403888a5ffab11444b82--560bebf06e3e46e4a742a85a00e0ce2c b6513f5bdb314606b0c135d0d86ecff7 RX(theta₁₄) 1dea952910a6403888a5ffab11444b82--b6513f5bdb314606b0c135d0d86ecff7 a1523be9282f4926b35c2d0fc9250ca5 RY(theta₁₈) b6513f5bdb314606b0c135d0d86ecff7--a1523be9282f4926b35c2d0fc9250ca5 686ffeb03154497890d2e4ebd51164e3 RX(theta₂₂) a1523be9282f4926b35c2d0fc9250ca5--686ffeb03154497890d2e4ebd51164e3 b132fb099f384e48a1ffab49c87c082f 686ffeb03154497890d2e4ebd51164e3--b132fb099f384e48a1ffab49c87c082f 7e8970e2de87439f827acb35573cbf3c X b132fb099f384e48a1ffab49c87c082f--7e8970e2de87439f827acb35573cbf3c 7e8970e2de87439f827acb35573cbf3c--f04907cf8a894431ac373af0248c1f9f 7e8970e2de87439f827acb35573cbf3c--73dfb1e0c00141fd84125346442e7e0a d0c091b5079047c1b0327182015149b8 a1fee463943b4068b69da00e92577dfe X 5f74b65f3e8f49e9bfc8b8d4e8791ba1--a1fee463943b4068b69da00e92577dfe fa74bee7ac374c6092b3953c286d3587 RX(theta₃) a1fee463943b4068b69da00e92577dfe--fa74bee7ac374c6092b3953c286d3587 7b6f610a4efd4f559e2e14d8a922e4cf RY(theta₇) fa74bee7ac374c6092b3953c286d3587--7b6f610a4efd4f559e2e14d8a922e4cf cc8f8387ea794a3ea2fe2764cc5a7c0a RX(theta₁₁) 7b6f610a4efd4f559e2e14d8a922e4cf--cc8f8387ea794a3ea2fe2764cc5a7c0a 606342449aa940eab905128b4151a674 X cc8f8387ea794a3ea2fe2764cc5a7c0a--606342449aa940eab905128b4151a674 606342449aa940eab905128b4151a674--ba4d6eca83814ad7a56f8b94d880d7fb ea53358ba500402eb5761a2da2e662b2 606342449aa940eab905128b4151a674--ea53358ba500402eb5761a2da2e662b2 2da3bf9817f242b3977799835de6466a RX(theta₁₅) ea53358ba500402eb5761a2da2e662b2--2da3bf9817f242b3977799835de6466a adaca6f50c324197b95145dd2f194a2e RY(theta₁₉) 2da3bf9817f242b3977799835de6466a--adaca6f50c324197b95145dd2f194a2e a8bfe24293a1455e8d66a669feb0473e RX(theta₂₃) adaca6f50c324197b95145dd2f194a2e--a8bfe24293a1455e8d66a669feb0473e 61f7bf26d77a43a28adaee773fb23dd3 X a8bfe24293a1455e8d66a669feb0473e--61f7bf26d77a43a28adaee773fb23dd3 61f7bf26d77a43a28adaee773fb23dd3--b132fb099f384e48a1ffab49c87c082f d853a4fac5fe49d4bcc05eafa6a82bf9 61f7bf26d77a43a28adaee773fb23dd3--d853a4fac5fe49d4bcc05eafa6a82bf9 d853a4fac5fe49d4bcc05eafa6a82bf9--d0c091b5079047c1b0327182015149b8
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, 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]])

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.2606+0.0076j, -0.4074+0.1547j,  0.5133-0.1015j, -0.0119-0.1060j,
          0.5207+0.0390j, -0.1361+0.2232j, -0.0205+0.0557j, -0.2464-0.2275j],
        [ 0.0011+0.0747j,  0.2227-0.3560j, -0.1053+0.0844j, -0.1065+0.5197j,
         -0.1590+0.2325j, -0.1133+0.1762j, -0.6188-0.0830j, -0.0578-0.0459j]])

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