Source code for qlearnkit.algorithms.qkmeans.qkmeans_circuit

import logging
import numpy as np

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister

logger = logging.getLogger(__name__)


def _map_function(x):
    r"""
    We map data feature values to :math:`\theta` and :math:`\phi` values using
    the following eqaution:

    .. math:: \phi = (x + 1) \frac{\pi}{2}

    where :math:`\phi` is the phase and :math:`\theta` the angle
    """
    return (x + 1) * np.pi / 2


def _map_features(input_point,
                  centroids,
                  n_centroids: int):
    r"""
    Map the input point and the centroids to :math:`\theta` and :math:`\phi` values
    via the :func:`_map_function` method.

    Args:
        input_point:
            Input point to map.
        centroids:
            Array of points to map.
        n_centroids:
            Number of centroids.
    Returns:
        Tuple containing input point and centroids mapped.
    """
    phi_centroids_list = []
    theta_centroids_list = []
    phi_input = _map_function(input_point[0])
    theta_input = _map_function(input_point[1])
    for i in range(0, n_centroids):
        phi_centroids_list.append(_map_function(centroids[i][0]))
        theta_centroids_list.append(_map_function(centroids[i][1]))
    return phi_input, theta_input, phi_centroids_list, theta_centroids_list


[docs]def construct_circuit(input_point: np.ndarray, centroids: np.ndarray, k: int) -> QuantumCircuit: """ Apply a Hadamard to the ancillary qubit and our mapped data points. Encode data points using U3 gate. Perform controlled swap to entangle the state with the ancillary qubit Apply another Hadamard gate to the ancillary qubit. .. parsed-literal:: ┌───┐ ┌───┐ |0anc>: ┤ H ├────────────■──────┤ H ├────────M └───┘ | └───┘ ┌───┐ ┌────┐ | |0>: ───┤ H ├───┤ U3 ├───X────────── └───┘ └────┘ | ┌───┐ ┌────┐ | |0>: ───┤ H ├───┤ U3 ├───X────────── └───┘ └────┘ Args: input_point: Input point from which calculate the distance. centroids: Array of points representing the centroids to calculate the distance to. k: Number of centroids. Returns: The quantum circuit created. """ phi_input, theta_input, phi_centroids_list, theta_centroids_list = \ _map_features(input_point, centroids, k) # We need 3 quantum registers, of size k one for a data point (input), # one for each centroid and one for each ancillary qreg_input = QuantumRegister(k, name='qreg_input') qreg_centroid = QuantumRegister(k, name='qreg_centroid') qreg_psi = QuantumRegister(k, name='qreg_psi') # Create a k bit ClassicalRegister to hold the result # of the measurements creg = ClassicalRegister(k, 'creg') # Create the quantum circuit containing our registers qc = QuantumCircuit(qreg_input, qreg_centroid, qreg_psi, creg, name='qc') for i in range(0, k): # Apply Hadamard qc.h(qreg_psi[i]) qc.h(qreg_input[i]) qc.h(qreg_centroid[i]) # Encode new point and centroid qc.u(theta_input, phi_input, 0, qreg_input[i]) qc.u(theta_centroids_list[i], phi_centroids_list[i], 0, qreg_centroid[i]) # Perform controlled swap qc.cswap(qreg_psi[i], qreg_input[i], qreg_centroid[i]) # Apply second Hadamard to ancillary qc.h(qreg_psi[i]) # Measure ancillary qc.measure(qreg_psi[i], creg[i]) return qc