|
| 1 | +# Quantum Kernel SVM on Iris (Setosa vs Versicolor) using PennyLane and scikit-learn |
| 2 | + |
| 3 | +import pennylane as qml |
| 4 | +from pennylane import numpy as np |
| 5 | +from sklearn import datasets |
| 6 | +from sklearn.preprocessing import StandardScaler |
| 7 | +from sklearn.decomposition import PCA |
| 8 | +from sklearn.model_selection import train_test_split |
| 9 | +from sklearn.svm import SVC |
| 10 | +from sklearn.metrics import accuracy_score, classification_report |
| 11 | + |
| 12 | +# Load Iris dataset and select two classes (0: setosa, 1: versicolor) |
| 13 | +iris = datasets.load_iris() |
| 14 | +X = iris.data |
| 15 | +y = iris.target |
| 16 | +mask = y != 2 # drop class '2' (virginica) |
| 17 | +X = X[mask] |
| 18 | +y = y[mask] |
| 19 | + |
| 20 | +# Standardize features and reduce to 2 dimensions via PCA |
| 21 | +scaler = StandardScaler() |
| 22 | +X_scaled = scaler.fit_transform(X) |
| 23 | +pca = PCA(n_components=2) |
| 24 | +X_reduced = pca.fit_transform(X_scaled) |
| 25 | + |
| 26 | +# Split into train and test sets |
| 27 | +X_train, X_test, y_train, y_test = train_test_split( |
| 28 | + X_reduced, y, test_size=0.2, random_state=42 |
| 29 | +) |
| 30 | +# Define quantum device and feature map (angle encoding on 2 qubits) |
| 31 | +n_qubits = 2 |
| 32 | +dev = qml.device('default.qubit', wires=n_qubits) |
| 33 | + |
| 34 | +@qml.qnode(dev) |
| 35 | +def feature_map(x): |
| 36 | + # Encode 2 features into rotation angles |
| 37 | + for i in range(n_qubits): |
| 38 | + qml.RY(x[i] * np.pi, wires=i) |
| 39 | + # Optional: add entanglement (e.g., ZZ interaction) |
| 40 | + qml.CNOT(wires=[0, 1]) |
| 41 | + qml.RZ((x[0] + x[1]) * np.pi, wires=1) |
| 42 | + qml.CNOT(wires=[0, 1]) |
| 43 | + return qml.state() |
| 44 | + |
| 45 | +# Compute quantum kernel (fidelity) between two feature vectors |
| 46 | +def quantum_kernel(x1, x2): |
| 47 | + # Compute state vectors for each input |
| 48 | + state1 = feature_map(x1) |
| 49 | + state2 = feature_map(x2) |
| 50 | + # Kernel = |<phi(x1)|phi(x2)>|^2 |
| 51 | + overlap = np.vdot(state1, state2) |
| 52 | + return np.abs(overlap) ** 2 |
| 53 | + |
| 54 | +# Build kernel (Gram) matrices for training and test sets |
| 55 | +n_train = len(X_train) |
| 56 | +n_test = len(X_test) |
| 57 | +kernel_train = np.zeros((n_train, n_train)) |
| 58 | +for i in range(n_train): |
| 59 | + for j in range(n_train): |
| 60 | + kernel_train[i, j] = quantum_kernel(X_train[i], X_train[j]) |
| 61 | + |
| 62 | +kernel_test = np.zeros((n_test, n_train)) |
| 63 | +for i in range(n_test): |
| 64 | + for j in range(n_train): |
| 65 | + kernel_test[i, j] = quantum_kernel(X_test[i], X_train[j]) |
| 66 | + |
| 67 | +# Train SVM with precomputed quantum kernel |
| 68 | +svm = SVC(kernel='precomputed') |
| 69 | +svm.fit(kernel_train, y_train) |
| 70 | + |
| 71 | +# Predict on test set and evaluate |
| 72 | +y_pred = svm.predict(kernel_test) |
| 73 | +acc = accuracy_score(y_test, y_pred) |
| 74 | +print("Test Accuracy:", acc) |
| 75 | +print("\nClassification Report:\n", classification_report(y_test, y_pred)) |
0 commit comments