<jupyter_start><jupyter_text>Quantum Nearest Neighbour: distance based multiclass classifier References: * Classifier: Implementing a distance-based classifier with a quantum interference circuit, M. Schuld et al 2017 EPL 119 60002* QRAM: Circuit-Based Quantum Random Access Memory for Classical Data, <NAME>, <NAME>, and <NAME>  Let's test the multiclass classifier with a simple data set  Preparing the data<jupyter_code>import numpy as np
from numpy import pi
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv("input_files/clusters.csv", usecols=["f0", "f1", "class"])
# Create binary variables to filter data
isGreen = data["class"] == 'Green'
isBlue = data["class"] == 'Blue'
isBlack = data["class"] == 'Black'
isYellow = data["class"] == "Yellow"

# Filter data
greenData = data[isGreen]#.drop(['Class'], axis=1)
blueData = data[isBlue]#.drop(['Class'], axis=1)
blackData = data[isBlack]#.drop(['Class'], axis=1)
yellowData = data[isYellow]
plt.plot(greenData["f0"], greenData["f1"], 'gx')
plt.plot(blueData["f0"], blueData["f1"], 'bx')
plt.plot(blackData["f0"], blackData["f1"], 'kx')
plt.plot(yellowData["f0"], yellowData["f1"], "yx")

plt.show()
def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0:
       return v
    return v / norm

for i in data.index:
    v = [data["f0"][i],data["f1"][i]]
    v = normalize(v)
    data.loc[i,"f0"], data.loc[i,"f1"] = v[0], v[1]
# Filter data
greenData = data[isGreen]#.drop(['Class'], axis=1)
blueData = data[isBlue]#.drop(['Class'], axis=1)
blackData = data[isBlack]#.drop(['Class'], axis=1)
yellowData = data[isYellow]
plt.plot(greenData["f0"], greenData["f1"], 'gx')
plt.plot(blueData["f0"], blueData["f1"], 'bx')
plt.plot(blackData["f0"], blackData["f1"], 'kx')
plt.plot(yellowData["f0"], yellowData["f1"], "yx")
# plt.savefig("Clusters/cluster.png", dpi=300)
plt.show()
# random_seed : int : Random number generator seed
random_seed = 1
rgen = np.random.RandomState(random_seed)
def _shuffle(self, X, y):
    """Shuffle training data"""
    r = self.rgen.permutation(len(y))
    return X[r], y[r]
greenRandom = greenData.iloc[rgen.permutation(len(greenData.index))].copy()
blueRandom = blueData.iloc[rgen.permutation(len(blueData.index))].copy()
blackRandom = blackData.iloc[rgen.permutation(len(blackData.index))].copy()
yellowRandom = yellowData.iloc[rgen.permutation(len(yellowData.index))].copy()

greenRandom.loc[:, "f0":"f1"] = greenRandom.loc[:,"f0":"f1"].apply(np.arcsin)
blueRandom.loc[:, "f0":"f1"] = blueRandom.loc[:,"f0":"f1"].apply(np.arcsin)
blackRandom.loc[:, "f0":"f1"] = blackRandom.loc[:,"f0":"f1"].apply(np.arcsin)
yellowRandom.loc[:, "f0":"f1"] = yellowRandom.loc[:,"f0":"f1"].apply(np.arcsin)

greenTraining = greenRandom.iloc[:2]
blueTraining = blueRandom.iloc[:2]
blackTraining = blackRandom.iloc[:2]
yellowTraining = yellowRandom.iloc[:2]

greenInput = greenRandom.iloc[2]
blueInput = blueRandom.iloc[2]
blackInput = blackRandom.iloc[2]
yellowInput = yellowRandom.iloc[2]

trainingArray = pd.concat([greenTraining, blueTraining, blackTraining, yellowTraining])
plt.plot(trainingArray["f0"], trainingArray["f1"], "x")
plt.plot(greenInput["f0"], greenInput["f1"], "gx")
plt.plot(blueInput["f0"], blueInput["f1"], "bx")
plt.plot(blackInput["f0"], blackInput["f1"], "kx")
plt.plot(yellowInput["f0"], yellowInput["f1"], "yx")
# plt.savefig("Clusters/random.png", dpi=300)
plt.show()<jupyter_output><empty_output><jupyter_text>Building the quantum circuit<jupyter_code>import qiskit
from qiskit import IBMQ
from qiskit import (
    QuantumCircuit,
    QuantumRegister,
    ClassicalRegister,
    execute,
    Aer)
from qiskit.visualization import plot_histogram
def encodeVector2(circuit, data, i, controls, rotationQubit, ancillaQubits):
    # |i> = |0>
    circuit.x(i)
    circuit.mcry(data[0], controls, rotationQubit, ancillaQubits)
    circuit.x(i)
    
    # |i> = |1>
    circuit.mcry(data[1], controls, rotationQubit, ancillaQubits)

def encodeClass(circuit, vectorClass):
    classSwitcher = {
        "Green": 0,
        "Blue": 1,
        "Black": 2,
        "Yellow": 3
    }
    
    # |c> = |00>
    if classSwitcher.get(vectorClass) == 0:
        circuit.x(c)
    # |c> = |01>
    elif classSwitcher.get(vectorClass) == 1:
        circuit.x(c[1])
    # |c> = |10>
    elif classSwitcher.get(vectorClass) == 2:
        circuit.x(c[0])
    # |c> = |11>
    elif classSwitcher.get(vectorClass) == 3:
        None

def encodeIndexBitwise3(circuit,index):
    """
    Encode the index of the training vectors with reason
    """
    
    zerosInIndex = index ^ 0b111
    
    if zerosInIndex & 0b001:
        circuit.x(m[0])
    if zerosInIndex & 0b010:
        circuit.x(m[1])
    if zerosInIndex & 0b100:
        circuit.x(m[2])

def encodeTraining(circuit, data, i, controls, rotationQubit, ancillaQubits, c, m):
    # Header
    encodeClass(circuit, c)
    encodeIndexBitwise3(circuit, m)
    
    # Encoder
    encodeVector2(circuit, data, i, controls, rotationQubit, ancillaQubits)
    
    # Footer
    encodeClass(circuit, c)
    encodeIndexBitwise3(circuit, m)

def buildTrainingState(trainingArray):
    """
    Given an array of up to 32 training vectors,
    build the quantum superposition state. 
    """
    for index in range(len(trainingArray.index)):
        trainingVector = trainingArray.iloc[index]
        encodeTraining(circuit, trainingVector["f0":"f1"], i, a[:]+i[:]+m[:]+c[:], r[0], q, trainingVector["class"], index)
a = QuantumRegister(1,'a') # knn ancilla
m = QuantumRegister(3,'m') # training vector index
i = QuantumRegister(1,'i') # feature index
r = QuantumRegister(1,'r') # rotation qubit
q = QuantumRegister(5,'q') # qram ancilla
c = QuantumRegister(2,'c') # class
b = ClassicalRegister(4, 'bit')
circuit = QuantumCircuit(a,m,i,r,q,c,b)

circuit.h(a)
circuit.h(m)
circuit.h(i)
circuit.h(c)

# >>> Encode the input vector >>>

encodeVector2(circuit, greenInput, i, a[:]+i[:], r[0], q)

circuit.x(a)

# <<< Encode the input vector <<<

# >>> Encode the training vectors >>>

buildTrainingState(trainingArray)

# <<< Encode the training vectors <<<

circuit.measure(r,b[0])

circuit.h(a)

circuit.measure(a,b[1])
circuit.measure(c[0],b[2])
circuit.measure(c[1],b[3])
simulator = Aer.get_backend('qasm_simulator')
job = execute(circuit, simulator, shots=8192)
result = job.result()
counts = result.get_counts(circuit)
print("\nTotal counts are:",counts)
# plot_histogram(counts)
goodCounts = {k: counts[k] for k in counts.keys() & {'0001','0101','1001','1101'}}
plot_histogram(goodCounts)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.17456207159177456, 'fraction_numerical': 0.025894897182025894, 'mean_word_length': 4.990875912408759, 'pattern_counts': {'":': 13, '<': 24, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '169659', 'license': 'Apache-2.0', 'n_tokens_mistral': 2521, 'n_tokens_neox': 2359, 'n_words': 493, 'path': 'artificial_intelligence/qnn_clusters.ipynb', 'repo_name': 'visika/qiskit-community-tutorials', 'size': '6601'}