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.73685371+0.36294684j 0.25202622-0.51166296j 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)
cluster_5a3bf50ff63c4ea7becf08bc290479f8 Circuit block cluster_f34472f52ed8481bbf4ded593d1fb364 Prep block 1b088fa1c04d477aa3bddbdadd65196d 0 658b4036075c46ca8b46eee3efdfd147 1b088fa1c04d477aa3bddbdadd65196d--658b4036075c46ca8b46eee3efdfd147 bd10a44ccb754386a3a077440a1a8add 1 2ce3fd53cc064087beac24e85862a971 RX(theta₀) 658b4036075c46ca8b46eee3efdfd147--2ce3fd53cc064087beac24e85862a971 2475feb5056b4f4391d8babfff889476 RY(theta₄) 2ce3fd53cc064087beac24e85862a971--2475feb5056b4f4391d8babfff889476 ae645c3ba1b749dfa89a804e1978835a RX(theta₈) 2475feb5056b4f4391d8babfff889476--ae645c3ba1b749dfa89a804e1978835a d351c808507942a6aedc722872f45168 ae645c3ba1b749dfa89a804e1978835a--d351c808507942a6aedc722872f45168 0cb87358a1e440b6ad5c4019541516f4 d351c808507942a6aedc722872f45168--0cb87358a1e440b6ad5c4019541516f4 8220474b2e7e47d0a8c0af9259843cf7 RX(theta₁₂) 0cb87358a1e440b6ad5c4019541516f4--8220474b2e7e47d0a8c0af9259843cf7 85ffb65607f74ab88d21dd73e3723109 RY(theta₁₆) 8220474b2e7e47d0a8c0af9259843cf7--85ffb65607f74ab88d21dd73e3723109 ff0a16fea8804328ab71b00b56a3d669 RX(theta₂₀) 85ffb65607f74ab88d21dd73e3723109--ff0a16fea8804328ab71b00b56a3d669 41a8fbbde2f14c479d5d1ffede30b8be ff0a16fea8804328ab71b00b56a3d669--41a8fbbde2f14c479d5d1ffede30b8be f7b88391bb514833a6839e2833549d01 41a8fbbde2f14c479d5d1ffede30b8be--f7b88391bb514833a6839e2833549d01 5413d394364f409ab9f9ffcc68368365 f7b88391bb514833a6839e2833549d01--5413d394364f409ab9f9ffcc68368365 cebb78be9226493e998a887eba44dbc2 b5d6df3922754b469ff3923164d4628a bd10a44ccb754386a3a077440a1a8add--b5d6df3922754b469ff3923164d4628a c8d9064dc8fe44f39bd77de0fb29f7ac 2 388d0170bd254a9cad28be9a418d8b74 RX(theta₁) b5d6df3922754b469ff3923164d4628a--388d0170bd254a9cad28be9a418d8b74 3dea7bdd524e46f2b125bcdc8bba93a0 RY(theta₅) 388d0170bd254a9cad28be9a418d8b74--3dea7bdd524e46f2b125bcdc8bba93a0 6d4a632e3f184e97945041af33b0ab45 RX(theta₉) 3dea7bdd524e46f2b125bcdc8bba93a0--6d4a632e3f184e97945041af33b0ab45 800e310ee14c41e88b30365e297521df X 6d4a632e3f184e97945041af33b0ab45--800e310ee14c41e88b30365e297521df 800e310ee14c41e88b30365e297521df--d351c808507942a6aedc722872f45168 ff092d7492a143e1b063adc04424416a 800e310ee14c41e88b30365e297521df--ff092d7492a143e1b063adc04424416a f05edf216ec04bb297b965db3d28791c RX(theta₁₃) ff092d7492a143e1b063adc04424416a--f05edf216ec04bb297b965db3d28791c 2e57b67b665c402ab61106acaf69578d RY(theta₁₇) f05edf216ec04bb297b965db3d28791c--2e57b67b665c402ab61106acaf69578d a1233d3f96ba4c14ae0800e8c5b51139 RX(theta₂₁) 2e57b67b665c402ab61106acaf69578d--a1233d3f96ba4c14ae0800e8c5b51139 8489153457234930997995732cb5a27c X a1233d3f96ba4c14ae0800e8c5b51139--8489153457234930997995732cb5a27c 8489153457234930997995732cb5a27c--41a8fbbde2f14c479d5d1ffede30b8be 42b8ccc7f42c4aac947a331bc8719d4a 8489153457234930997995732cb5a27c--42b8ccc7f42c4aac947a331bc8719d4a 42b8ccc7f42c4aac947a331bc8719d4a--cebb78be9226493e998a887eba44dbc2 8bc29414100f4a6385ecdb4aa8e96d14 f966b00831294b06a88ec103130a5362 c8d9064dc8fe44f39bd77de0fb29f7ac--f966b00831294b06a88ec103130a5362 43effcde7bdd488f8e5b1863a921aa7e 3 f789fa1a9e4f4b1cb6de24403c05723e RX(theta₂) f966b00831294b06a88ec103130a5362--f789fa1a9e4f4b1cb6de24403c05723e dac723f3e77f43768b8c385d07ad46c4 RY(theta₆) f789fa1a9e4f4b1cb6de24403c05723e--dac723f3e77f43768b8c385d07ad46c4 6e5eeaf36f164baca14494c001d2e2c6 RX(theta₁₀) dac723f3e77f43768b8c385d07ad46c4--6e5eeaf36f164baca14494c001d2e2c6 50a856f3bf10430e8a923c3f3435eda1 6e5eeaf36f164baca14494c001d2e2c6--50a856f3bf10430e8a923c3f3435eda1 af3bfa5bc3724fc0bce09ec4b8a9d7a1 X 50a856f3bf10430e8a923c3f3435eda1--af3bfa5bc3724fc0bce09ec4b8a9d7a1 af3bfa5bc3724fc0bce09ec4b8a9d7a1--ff092d7492a143e1b063adc04424416a c0c571172c684f8a93ce71f8793b6385 RX(theta₁₄) af3bfa5bc3724fc0bce09ec4b8a9d7a1--c0c571172c684f8a93ce71f8793b6385 af0c5246e51840888f6adb995c401101 RY(theta₁₈) c0c571172c684f8a93ce71f8793b6385--af0c5246e51840888f6adb995c401101 d731d69129e549ea87d9293d43face44 RX(theta₂₂) af0c5246e51840888f6adb995c401101--d731d69129e549ea87d9293d43face44 c54f7e58275248c4b553b4c5036c0f7d d731d69129e549ea87d9293d43face44--c54f7e58275248c4b553b4c5036c0f7d e12111c4e4e446f4a0012b8025dd65b2 X c54f7e58275248c4b553b4c5036c0f7d--e12111c4e4e446f4a0012b8025dd65b2 e12111c4e4e446f4a0012b8025dd65b2--42b8ccc7f42c4aac947a331bc8719d4a e12111c4e4e446f4a0012b8025dd65b2--8bc29414100f4a6385ecdb4aa8e96d14 08beb1d26d2b4a3b8c536d327de97479 42214aaf26f64705b7994138e25bb87c X 43effcde7bdd488f8e5b1863a921aa7e--42214aaf26f64705b7994138e25bb87c 65fe5c27bc3a4f3cb532ea125709c19c RX(theta₃) 42214aaf26f64705b7994138e25bb87c--65fe5c27bc3a4f3cb532ea125709c19c 0af93286f6754187a0ec699aa2ffee12 RY(theta₇) 65fe5c27bc3a4f3cb532ea125709c19c--0af93286f6754187a0ec699aa2ffee12 c9925c678955447b8652506e4cb123ee RX(theta₁₁) 0af93286f6754187a0ec699aa2ffee12--c9925c678955447b8652506e4cb123ee c785b6d8d34c45ee95b9dca98c4159c4 X c9925c678955447b8652506e4cb123ee--c785b6d8d34c45ee95b9dca98c4159c4 c785b6d8d34c45ee95b9dca98c4159c4--50a856f3bf10430e8a923c3f3435eda1 b165cb6ea15c416ea6386d93d83d7392 c785b6d8d34c45ee95b9dca98c4159c4--b165cb6ea15c416ea6386d93d83d7392 d11b023edff2426e88f140dd45c7dd05 RX(theta₁₅) b165cb6ea15c416ea6386d93d83d7392--d11b023edff2426e88f140dd45c7dd05 c5341e04407847c2a2258c54370f237b RY(theta₁₉) d11b023edff2426e88f140dd45c7dd05--c5341e04407847c2a2258c54370f237b f1067e3ca73b414795713564038af403 RX(theta₂₃) c5341e04407847c2a2258c54370f237b--f1067e3ca73b414795713564038af403 c0aa9c39df0c41d496ea95000888ea28 X f1067e3ca73b414795713564038af403--c0aa9c39df0c41d496ea95000888ea28 c0aa9c39df0c41d496ea95000888ea28--c54f7e58275248c4b553b4c5036c0f7d 1554b74e54674447b750102d8f9e40ac c0aa9c39df0c41d496ea95000888ea28--1554b74e54674447b750102d8f9e40ac 1554b74e54674447b750102d8f9e40ac--08beb1d26d2b4a3b8c536d327de97479
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, 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, 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 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.3807+0.3202j, -0.2349+0.0810j, -0.3754+0.1022j,  0.5541+0.2234j,
         -0.1159+0.1347j, -0.2595+0.1589j, -0.1146-0.0531j, -0.1842-0.0918j],
        [-0.2709+0.2965j, -0.0363-0.1403j, -0.0893+0.3857j, -0.2192+0.0857j,
          0.3617+0.1455j,  0.2482-0.3901j,  0.1752-0.3836j,  0.1884-0.1628j]])

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