Quantum Machine Learning Tutorial

A Hands-on Tutorial for Machine Learning Practitioners and Researchers

Data Encoding

Code Demonstration

This section provides code implementations for key techniques introduced earlier, including quantum read-in strategies and block encoding, to give readers the opportunity to practice and deepen their understanding.

Read-in implementations

This subsection demonstrates toy examples of implementing data encoding methods in quantum computing, as discussed in earlier sections. Specifically, we cover basis encoding, amplitude encoding, and angle encoding. These examples aim to provide readers with hands-on experience in applying quantum data encoding techniques.

Basis encoding

PennyLane provides built-in support for basis encoding through its BasisEmbedding function. Below is the Python code demonstrating the basis encoding for the integer 6.

import pennylane as qml

dev = qml.device("default.qubit", range(3))
@qml.qnode(dev)
def circuit(x):
		qml.BasisEmbedding(x, range(3))
		return qml.state()

# Call the function
circuit(6)

Amplitude encoding

PennyLane offers built-in support for amplitude encoding via the AmplitudeEmbedding function. Below is a Python example demonstrating amplitude encoding for a randomly generated complex vector.

import pennylane as qml
import numpy as np

# Number of qubits
n_qubits = 8

# Define a quantum device with 8 qubits
dev = qml.device("default.qubit", wires=n_qubits)

@qml.qnode(dev)
def circuit(x):
    qml.AmplitudeEmbedding(features=x, wires=range(n_qubits), normalize=True, pad_with=0.)
    return qml.state()

# Generate a random complex vector of length 2^n_qubits
x_real = np.random.normal(loc=0, scale=1.0, size=2**n_qubits)
x_imag = np.random.normal(loc=0, scale=1.0, size=2**n_qubits)
x = x_real + 1j * x_imag

# Execute the circuit to encode the vector as a quantum state
circuit(x)

Angle encoding

PennyLane provides built-in support for angle encoding via the AngleEmbedding function. Below is a Python example demonstrating angle encoding for a randomly generated real vector.

import pennylane as qml
import numpy as np

# Number of qubits
n_qubits = 8

# Define a quantum device with 8 qubits
dev = qml.device("default.qubit", wires=n_qubits)

@qml.qnode(dev)
def circuit(x):
    qml.AngleEmbedding(features=x, wires=range(n_qubits), rotation="X")
    return qml.state()

# Generate a random real vector of length n_qubits
x = np.random.uniform(0, np.pi, (n_qubits))

# Execute the circuit to encode the vector as a quantum state
circuit(x)

Block encoding

Here, we provide an example of how we may construct a block encoding. We construct the block encoding via the linear combination. We use PennyLane to keep consistency, yet there are many other platforms that are available as well. Please note that it is time-consuming to do the Pauli decomposition (for $n$-qubit matrix, it takes time $\mathcal{O}(n4^n)$), so we suggest not trying a large matrix with this method.

import numpy as np
import pennylane as qml
import matplotlib.pyplot as plt

a = 0.36
b = 0.64

# matrix to be decomposed
A = np.array(
    [[a,  0, 0,  b],
     [0, -a, b,  0],
     [0,  b, a,  0],
     [b,  0, 0, -a]]
)

# decompose the matrix into sum of Pauli strings
LCU = qml.pauli_decompose(A)
LCU_coeffs, LCU_ops = LCU.terms()

# normalized square roots of coefficients
alphas = (np.sqrt(LCU_coeffs) / np.linalg.norm(np.sqrt(LCU_coeffs)))

dev = qml.device("default.qubit", wires=3)

# unitaries
ops = LCU_ops
# relabeling wires: 0 --> 1, and 1 --> 2
unitaries = [qml.map_wires(op, {0: 1, 1: 2}) for op in ops]

@qml.qnode(dev)
def lcu_circuit():  # block_encode
    # PREP
    qml.StatePrep(alphas, wires=0)

    # SEL
    qml.Select(unitaries, control=0)

    # PREP_dagger
    qml.adjoint(qml.StatePrep(alphas, wires=0))
    return qml.state()

print(np.real(np.round(output_matrix,2)))