Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.2k stars 2.36k forks source link

Qiskit function to encode Python list of integers into quantum state #8290

Closed SimoneGasperini closed 2 years ago

SimoneGasperini commented 2 years ago

Suppose I am given the following Python list/array as an example:

arr = [2, 1, 2, 0, 0, 1, 3, 2]

To encode this data into a quantum state I can use the "bit-string basis encoding" technique, writing both the integer elements and the integer indices of arr as binary strings $s \in \{ 0,1 \}^*$ and then transforming them into a quantum state on the computational basis. In this case, I would need $n=3$ qubits to encode the indices $i=0,\dots,N-1$ with $N=2^n=8$ and $n_*=2$ more qubits to encode the digits $\mathrm{arr}_i\in \{ 0,1,2,3 \}$, ending up with the following state:

$$|\psi \rangle = \frac{1}{\sqrt{N}} \sum_{i=0}^{N-1} |\mathrm{arr}_i \rangle |i\rangle$$

The Qiskit code implementing the quantum circuit to prepare the state $|\psi \rangle$ would look like this:

from qiskit import QuantumRegister, QuantumCircuit
from qiskit.circuit.library.standard_gates import C3XGate

qr1 = QuantumRegister(size=3, name='index')
qr2 = QuantumRegister(size=2, name='element')

encoder = QuantumCircuit(qr1, qr2)
encoder.h(qr1)
encoder.append(C3XGate(ctrl_state='000'), [*qr1, qr2[1]])
encoder.append(C3XGate(ctrl_state='001'), [*qr1, qr2[0]])
encoder.append(C3XGate(ctrl_state='010'), [*qr1, qr2[1]])
encoder.append(C3XGate(ctrl_state='101'), [*qr1, qr2[0]])
encoder.append(C3XGate(ctrl_state='110'), [*qr1, qr2[0]])
encoder.append(C3XGate(ctrl_state='110'), [*qr1, qr2[1]])
encoder.append(C3XGate(ctrl_state='111'), [*qr1, qr2[1]])

encoder.draw('mpl')

circ

Questions: 1) Is this correct? Are there more efficient techniques for data encoding? 2) Does Qiskit provide any functionality to automatically prepare the quantum state given a generic Python list?

Cryoris commented 2 years ago
  1. I'm not an expert on which would be the most efficient way of synthesizing this network (@ShellyGarion or @alexanderivrii would certainly know more!) but conceptually this looks correct to me. In general there are different techniques to encode numbers into quantum states, here you mention basis encoding but there's also amplitude encoding, phase encoding, angle encoding... depending on your use case either might be better! This would only change what you control though, not the logic on the index register.
  2. There's currently no functionality to encode a list of numbers, no. But if there's a common use-case where this is required we can certainly discuss adding it 🙂
InfamousPlatypus commented 2 years ago

I would appreciate a way to encode lists of numbers, if nothing else it would be helpful for debugging.

ShellyGarion commented 2 years ago

I think that we do not have such an encoding in the circuit library yet. However, you can encode your data (after normalizing it) as a quantum state using the StatePreparation class. See this code for example:

import numpy as np
from qiskit.circuit.library import StatePreparation
from qiskit.quantum_info import Statevector

arr = [2, 1, 2, 0, 0, 1, 3, 2]
norm = np.linalg.norm(arr)

SP = StatePreparation(arr / norm)
print(SP)

qc = QuantumCircuit(3)
qc.append(SP, [0,1,2])
print (qc)
print(qc.decompose().decompose().decompose().decompose().decompose())

print (Statevector(qc))
SimoneGasperini commented 2 years ago

Ok thank you @ShellyGarion! So there we are actually implementing "amplitude encoding", right? I run that circuit by using the qasm_simulator backend and the final measurements on the 3-qubits-system are the following: hist

Makes sense! The probabilities seems indeed to correspond to the square of each entry in the original (normalized) array:

(arr / norm)**2 = [0.174, 0.043, 0.174, 0.0, 0.0, 0.043, 0.391, 0.174]

jakelishman commented 2 years ago

This issue seems to have been resolved, as far as I can see? I'll close it now, but please feel free to re-open, or make a new issue if there's more to discuss.

SimoneGasperini commented 1 year ago

A general procedure to encode a list/array of non-negative numbers (e.g. arr = [2, 1, 2, 0, 0, 1, 3, 2] in the quantum state $|\psi\rangle$ (basis encoding) could be implemented as follows:

import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit.library import StatePreparation

len_qr1 = int(np.ceil(np.log2(len(arr))))   # index quantum register
len_qr2 = int(np.log2(max(arr))) + 1        # element quantum register
num_qubits = len_qr1 + len_qr2
statevector = np.zeros(2**num_qubits)

for i, el in enumerate(arr):
    index_reg = '{0:b}'.format(i).zfill(len_qr1)
    element_reg = '{0:b}'.format(el).zfill(len_qr2)
    statevector[int(element_reg + index_reg, 2)] = 1

statevector /= np.linalg.norm(statevector)   # normalization

qc = QuantumCircuit(num_qubits)
sp = StatePreparation(statevector)
qc.append(sp, range(num_qubits))
from qiskit import Aer, execute
from qiskit.visualization import plot_histogram

qc.measure_all()

backend = Aer.get_backend('qasm_simulator')
job = execute(qc, backend=backend, shots=10000)
counts = job.result().get_counts()
plot_histogram(counts)

output

PS: this works properly only if $\mathrm{len}(\mathrm{arr})$ is a power of 2 (could be generalized with a bit of work) and it requires a number of qubits $$N\sim\log_2(\mathrm{len}(\mathrm{arr})) + \log_2(\mathrm{max}(\mathrm{arr}))$$