diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8618d04 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +.ipynb_checkpoints +~*.docx \ No newline at end of file diff --git a/.ipynb_checkpoints/examples-checkpoint.ipynb b/.ipynb_checkpoints/examples-checkpoint.ipynb deleted file mode 100644 index 91fd780..0000000 --- a/.ipynb_checkpoints/examples-checkpoint.ipynb +++ /dev/null @@ -1,251 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 23, - "id": "4d3113ae", - "metadata": {}, - "outputs": [], - "source": [ - "import cirq\n", - "import numpy as np\n", - "import pickle\n", - "import json\n", - "import os\n", - "from collections import Counter\n", - "from sklearn.metrics import mean_squared_error\n", - "\n", - "#define utility functions\n", - "\n", - "def simulate(circuit: cirq.Circuit) -> dict:\n", - " \"\"\"This funcion simulate a cirq circuit (without measurement) and output results in the format of histogram.\n", - " \"\"\"\n", - " simulator = cirq.Simulator()\n", - " result = simulator.simulate(circuit)\n", - " \n", - " state_vector=result.final_state_vector\n", - " \n", - " histogram = dict()\n", - " for i in range(len(state_vector)):\n", - " population = abs(state_vector[i]) ** 2\n", - " if population > 1e-9:\n", - " histogram[i] = population\n", - " \n", - " return histogram\n", - "\n", - "\n", - "def histogram_to_category(histogram):\n", - " \"\"\"This function take a histogram representations of circuit execution results, and process into labels as described in \n", - " the problem description.\"\"\"\n", - " assert abs(sum(histogram.values())-1)<1e-8\n", - " positive=0\n", - " for key in histogram.keys():\n", - " digits = bin(int(key))[2:].zfill(20)\n", - " if digits[-1]=='0':\n", - " positive+=histogram[key]\n", - " \n", - " return positive\n", - "\n", - "def count_gates(circuit: cirq.Circuit):\n", - " \"\"\"Returns the number of 1-qubit gates, number of 2-qubit gates, number of 3-qubit gates....\"\"\"\n", - " counter=Counter([len(op.qubits) for op in circuit.all_operations()])\n", - " \n", - " #feel free to comment out the following two lines. But make sure you don't have k-qubit gates in your circuit\n", - " #for k>2\n", - " for i in range(2,20):\n", - " assert counter[i]==0\n", - " \n", - " return counter\n", - "\n", - "def image_mse(image1,image2):\n", - " # Using sklearns mean squared error:\n", - " # https://scikit-learn.org/stable/modules/generated/sklearn.metrics.mean_squared_error.html\n", - " return mean_squared_error(image1, image2)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "82f90e0d", - "metadata": {}, - "outputs": [], - "source": [ - "#load the mock data (for testing only)\n", - "files=os.listdir(\"mock_data\")\n", - "dataset=list()\n", - "for file in files:\n", - " with open('mock_data/'+file, \"r\") as infile:\n", - " loaded = json.load(infile)\n", - " dataset.append(loaded)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "cb96a334", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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TL/2P70zzjuBVMJacAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEwM+Q+kA/7R+JXd3pn2P2R5Z8YEI94ZSerq9//hiFOz/BdY/ai7xDuTHvRfKHU4F2X9j48meWeukf8Cpkgd3AEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEywGjaGVX9rm3fmd+3l3pmbc//DOyNJ//aZ/7FOR3K8M1OyTntnWnvD3pmoC3hnLuT8/29aXJ/QoXAF4w4IAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACRYjxYjXHsn2zpSmf5bQsW7IbfbO/PlcSULH8jUuvdc7E4mmJXSsnmiGdybnr13eGeedQCrhDggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJFiPFiPf+J1O9M3fk70voWH/rH+uduX7sMe9MIot9JiLiEvsrfrp/nHcmeD7inRnwTiCVcAcEADBBAQEATHgX0O7du3XrrbeqpKREgUBA27Zti3veOacnnnhCxcXFysrKUmVlpY4cOZKseQEAKcK7gLq7u1VeXq66urpBn9+wYYOef/55vfjii9q3b5/Gjh2rxYsXq6en57KHBQCkDu9XKKuqqlRVVTXoc845Pffcc3rssce0dOlSSdJLL72kwsJCbdu2TXfeeeflTQsASBlJfQ2oublZra2tqqysjD0WDodVUVGhPXv2DJrp7e1VZ2dn3AYASH1JLaDW1lZJUmFhYdzjhYWFsee+qLa2VuFwOLaVlpYmcyQAwAhl/i64mpoadXR0xLaWlhbrkQAAwyCpBVRUVCRJamtri3u8ra0t9twXhUIh5ebmxm0AgNSX1AIqKytTUVGRdu7cGXuss7NT+/bt07x585J5KADAKOf9Lriuri41NTXFPm5ubtbBgweVl5enyZMna+3atfr5z3+ua665RmVlZXr88cdVUlKiZcuWJXNuAMAo511A+/fv1y233BL7eN26dZKkFStWaPPmzXrkkUfU3d2t1atXq729XTfddJN27NihMWPGJG9qAMCo511A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qKNHj2ratGnDPeagRvyX4PLz85WWlnbRu1ja2tpUVFRkNNXIMH78eF177bVqamqyHsXM59cA18fFpk6dqvz8/JS8PtasWaO3335b7733XtyPbykqKlJfX5/a29vj9k/V6+FS52EwFRUVkjSirocRX0CZmZmaM2eOdu7cGXssGo1q586dmjdvnuFk9rq6unT06FEVFxdbj2KmrKxMRUVFcddHZ2en9u3bd8VfH8ePH9eZM2dS6vpwzmnNmjXaunWrdu3apbKysrjn58yZo4yMjLjrobGxUceOHUup6+GrzsNgDh48KEkj63qwfhfEP+PVV191oVDIbd682f35z392q1evduPHj3etra3Wow2rH//4x66+vt41Nze7P/zhD66ystLl5+e7U6dOWY82pM6ePes+/PBD9+GHHzpJ7tlnn3Uffvih++STT5xzzv3iF79w48ePd9u3b3eHDh1yS5cudWVlZe78+fPGkyfXl52Hs2fPuocfftjt2bPHNTc3u3fffdd961vfctdcc43r6emxHj1pHnjgARcOh119fb07efJkbDt37lxsn/vvv99NnjzZ7dq1y+3fv9/NmzfPzZs3z3Dq5Puq89DU1OSefvppt3//ftfc3Oy2b9/upk6d6ubPn288ebxRUUDOOffCCy+4yZMnu8zMTDd37ly3d+9e65GG3R133OGKi4tdZmam+9rXvubuuOMO19TUZD3WkHvvvfecpIu2FStWOOcuvBX78ccfd4WFhS4UCrmFCxe6xsZG26GHwJedh3PnzrlFixa5iRMnuoyMDDdlyhS3atWqlPtP2mC/f0lu06ZNsX3Onz/vfvjDH7qrrrrKZWdnu9tuu82dPHnSbugh8FXn4dixY27+/PkuLy/PhUIhd/XVV7uf/OQnrqOjw3bwL+DHMQAATIz414AAAKmJAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACAif8H8OZooPKJKDYAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "#load the actual hackthon data (fashion-mnist)\n", - "images=np.load('data/images.npy')\n", - "labels=np.load('data/labels.npy')\n", - "#you can visualize it\n", - "import matplotlib.pyplot as plt\n", - "plt.imshow(images[1100])" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "b02b160e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.0\n" - ] - } - ], - "source": [ - "#submission part 1\n", - "\n", - "#load the definition of the encoder and decoder\n", - "from part1 import encode,decode\n", - "\n", - "n=len(dataset)\n", - "mse=0\n", - "gatecount=0\n", - "\n", - "for data in dataset:\n", - " #encode image into circuit\n", - " circuit=encode(data['image'])\n", - " \n", - " #simulate circuit\n", - " histogram=simulate(circuit)\n", - " \n", - " #count the number of 2-qubit gates\n", - " gatecount+=count_gates(circuit)[2]\n", - " \n", - " #reconstruct the image\n", - " image_re=decode(histogram)\n", - " \n", - " #calculate mse\n", - " mse+=image_mse(data['image'],image_re)\n", - " \n", - "#fidelity of reconstruction\n", - "f=1-mse\n", - "gatecount=gatecount/n\n", - "\n", - "#score for part1 \n", - "print(f*(0.999**gatecount))" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "2fe52c43", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.0\n" - ] - } - ], - "source": [ - "#grade part 2\n", - "\n", - "#load classifier circuit\n", - "with open('part2.pickle', 'rb') as f:\n", - " classifier=pickle.load(f)\n", - " \n", - "score=0\n", - "\n", - "\n", - "for data in dataset:\n", - " #encode image into circuit\n", - " circuit=encode(data['image'])\n", - " \n", - " #append with classifier circuit\n", - " \n", - " circuit.append(classifier)\n", - " \n", - " #simulate circuit\n", - " histogram=simulate(circuit)\n", - " \n", - " #count the gate used in the circuit for score calculation\n", - " gatecount+=count_gates(circuit)[2]\n", - " \n", - " #convert histogram to category\n", - " cat=histogram_to_category(histogram)\n", - " \n", - " if cat==data['category']:\n", - " score+=1\n", - "#score\n", - "score=score/n\n", - "gatecount=gatecount/n\n", - "\n", - "print(score*(0.999**gatecount))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "de96fdf1", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.0" - }, - "vscode": { - "interpreter": { - "hash": "1a1af0ee75eeea9e2e1ee996c87e7a2b11a0bebd85af04bb136d915cefc0abce" - } - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/.ipynb_checkpoints/part1_example_cirq-checkpoint.ipynb b/.ipynb_checkpoints/part1_example_cirq-checkpoint.ipynb deleted file mode 100644 index c3d383b..0000000 --- a/.ipynb_checkpoints/part1_example_cirq-checkpoint.ipynb +++ /dev/null @@ -1,226 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 8, - "id": "9c97e0dc", - "metadata": {}, - "outputs": [], - "source": [ - "import cirq\n", - "import numpy as np\n", - "import pickle\n", - "import json\n", - "import os\n", - "from collections import Counter\n", - "from sklearn.metrics import mean_squared_error\n", - "\n", - "#define utility functions\n", - "\n", - "def simulate(circuit: cirq.Circuit) -> dict:\n", - " \"\"\"This funcion simulate a cirq circuit (without measurement) and output results in the format of histogram.\n", - " \"\"\"\n", - " simulator = cirq.Simulator()\n", - " result = simulator.simulate(circuit)\n", - " \n", - " state_vector=result.final_state_vector\n", - " \n", - " histogram = dict()\n", - " for i in range(len(state_vector)):\n", - " population = abs(state_vector[i]) ** 2\n", - " if population > 1e-9:\n", - " histogram[i] = population\n", - " \n", - " return histogram\n", - "\n", - "\n", - "def histogram_to_category(histogram):\n", - " \"\"\"This function take a histogram representations of circuit execution results, and process into labels as described in \n", - " the problem description.\"\"\"\n", - " assert abs(sum(histogram.values())-1)<1e-8\n", - " positive=0\n", - " for key in histogram.keys():\n", - " digits = bin(int(key))[2:].zfill(20)\n", - " if digits[-1]=='0':\n", - " positive+=histogram[key]\n", - " \n", - " return positive\n", - "\n", - "def count_gates(circuit: cirq.Circuit):\n", - " \"\"\"Returns the number of 1-qubit gates, number of 2-qubit gates, number of 3-qubit gates....\"\"\"\n", - " counter=Counter([len(op.qubits) for op in circuit.all_operations()])\n", - " \n", - " #feel free to comment out the following two lines. But make sure you don't have k-qubit gates in your circuit\n", - " #for k>2\n", - " for i in range(2,20):\n", - " assert counter[i]==0\n", - " \n", - " return counter\n", - "\n", - "def image_mse(image1,image2):\n", - " # Using sklearns mean squared error:\n", - " # https://scikit-learn.org/stable/modules/generated/sklearn.metrics.mean_squared_error.html\n", - " return mean_squared_error(image1, image2)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "7f19ddcc", - "metadata": {}, - "outputs": [], - "source": [ - "#load the mock data (for testing only)\n", - "files=os.listdir(\"mock_data\")\n", - "dataset=list()\n", - "for file in files:\n", - " with open('mock_data/'+file, \"r\") as infile:\n", - " loaded = json.load(infile)\n", - " dataset.append(loaded)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "a443b6a8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGdCAYAAABU0qcqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAej0lEQVR4nO3dfXCU9d3v8c9uHpYEksUQ8lQCDajQCsS7VFJGpVhygHTGAeX0+HRmwOOB0QanSK2edFTUdia9cY51dFL8p4U6Iz7NCBy9O/QomDC2QG9QhmFqcxMaJdyQINgkJJBkk/2dPzhuuxK0v2WTb7K8XzPXDNm9Prm+XFzw4cpufgk455wAABhmQesBAABXJgoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJtKtB/iiaDSqEydOKCcnR4FAwHocAIAn55zOnj2rkpISBYOXvs8ZcQV04sQJlZaWWo8BALhMLS0tmjRp0iWfH3EFlJOTI0m6Sd9XujKMp0GypU+59MV4KUdXlnhnCq5v885I0om/TvTOZJ5O884EI94RnZ/iH7rtXz7wP5CkXcev9c5MfCaBf04O/Nk/gxGvXxG9r9/F/j2/lCEroLq6Oj3zzDNqbW1VeXm5XnjhBc2dO/crc59/2S1dGUoPUECpJj0Y8s4Ex4zxP85Y/+NIUjDL/1hpYxIooARefQ1m+R8nNC6xv0Np2f7nLz09gWPxdzw1/f8VRr/qZZQheRPCa6+9pnXr1mn9+vX64IMPVF5ersWLF+vUqVNDcTgAwCg0JAX07LPPatWqVbr33nv1zW9+Uy+++KKys7P1m9/8ZigOBwAYhZJeQH19fTpw4IAqKyv/fpBgUJWVldqzZ89F+/f29qqzszNuAwCkvqQX0OnTpzUwMKDCwsK4xwsLC9Xa2nrR/rW1tQqHw7GNd8ABwJXB/BtRa2pq1NHREdtaWlqsRwIADIOkvwsuPz9faWlpamuLfxtsW1ubioqKLto/FAopFErsHUsAgNEr6XdAmZmZmjNnjnbu3Bl7LBqNaufOnZo3b16yDwcAGKWG5PuA1q1bpxUrVujb3/625s6dq+eee07d3d269957h+JwAIBRaEgK6I477tCnn36qJ554Qq2trbr++uu1Y8eOi96YAAC4cgWcc856iH/U2dmpcDisBVrKSggp6OOf+38Zdtt//9/emT+en+qdkaTSjDPemUXZCayrk4D/053tnWnqvfh113/Gf8s95J25+f+u9c5c+z/3e2cw8vW7iOq1XR0dHcrNzb3kfubvggMAXJkoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYGJLVsIFLKdo74J359/862TtzrG+Cd0aS2iJh78zurkzvTFog6p0JBfq9MxGX5p2RpH09Jd6Z7L/6nwdc2bgDAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYYDVsDKustvPemYjzv0wTWTlaknLSerwz2Wm9CR1rOHT0ZyeUS2QV7fTuhA6FKxh3QAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEywGCmGVbDjnHfm+2ObvDN1n83zzkiJLUaayMKdGYGBYcmci2Z6ZySpOxryzoxtjSZ0LFy5uAMCAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABggsVIMaw6yvO9M//eW+Cd6RrwX0xTknqjeQnlfEVdYFiO81lkbEK5SZl/886cvMV/MdKc17wjSCHcAQEATFBAAAATSS+gJ598UoFAIG6bMWNGsg8DABjlhuQ1oOuuu07vvvvu3w+SzktNAIB4Q9IM6enpKioqGopPDQBIEUPyGtCRI0dUUlKiqVOn6p577tGxY8cuuW9vb686OzvjNgBA6kt6AVVUVGjz5s3asWOHNm7cqObmZt188806e/bsoPvX1tYqHA7HttLS0mSPBAAYgZJeQFVVVfrBD36g2bNna/Hixfrd736n9vZ2vf7664PuX1NTo46OjtjW0tKS7JEAACPQkL87YPz48br22mvV1NQ06POhUEihUGLfNAgAGL2G/PuAurq6dPToURUXFw/1oQAAo0jSC+jhhx9WQ0ODPv74Y/3xj3/UbbfdprS0NN11113JPhQAYBRL+pfgjh8/rrvuuktnzpzRxIkTddNNN2nv3r2aOHFisg8FABjFkl5Ar776arI/JVLJfZ96R76W3u6dCQX7vTOSlBEY8M4ksrBofmaXd+ZYr/9CqTnpPd4ZSepx/v80TL/2P70zzjuBVMJacAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEwM+Q+kA/7R+JXd3pn2P2R5Z8YEI94ZSerq9//hiFOz/BdY/ai7xDuTHvRfKHU4F2X9j48meWeukf8Cpkgd3AEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEywGjaGVX9rm3fmd+3l3pmbc//DOyNJ//aZ/7FOR3K8M1OyTntnWnvD3pmoC3hnLuT8/29aXJ/QoXAF4w4IAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACRYjxYjXHsn2zpSmf5bQsW7IbfbO/PlcSULH8jUuvdc7E4mmJXSsnmiGdybnr13eGeedQCrhDggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJFiPFiPf+J1O9M3fk70voWH/rH+uduX7sMe9MIot9JiLiEvsrfrp/nHcmeD7inRnwTiCVcAcEADBBAQEATHgX0O7du3XrrbeqpKREgUBA27Zti3veOacnnnhCxcXFysrKUmVlpY4cOZKseQEAKcK7gLq7u1VeXq66urpBn9+wYYOef/55vfjii9q3b5/Gjh2rxYsXq6en57KHBQCkDu9XKKuqqlRVVTXoc845Pffcc3rssce0dOlSSdJLL72kwsJCbdu2TXfeeeflTQsASBlJfQ2oublZra2tqqysjD0WDodVUVGhPXv2DJrp7e1VZ2dn3AYASH1JLaDW1lZJUmFhYdzjhYWFsee+qLa2VuFwOLaVlpYmcyQAwAhl/i64mpoadXR0xLaWlhbrkQAAwyCpBVRUVCRJamtri3u8ra0t9twXhUIh5ebmxm0AgNSX1AIqKytTUVGRdu7cGXuss7NT+/bt07x585J5KADAKOf9Lriuri41NTXFPm5ubtbBgweVl5enyZMna+3atfr5z3+ua665RmVlZXr88cdVUlKiZcuWJXNuAMAo511A+/fv1y233BL7eN26dZKkFStWaPPmzXrkkUfU3d2t1atXq729XTfddJN27NihMWPGJG9qAMCo511ACxYskHPuks8HAgE9/fTTevrppy9rMOBzkR7/BTV7XGKLfUZcmndmwA3Pe3kyAv5Ld44J+i8QKkklGX/zzuzLuj6hY+HKZf4uOADAlYkCAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYMJ/mWFgmP2Xb3zknfm0P7GfrJvIathtkbB3piTTf7XpMQH/la1bInneGUnKC3V5Z9qe8F+tu2CpdwQphDsgAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJliMFCPe1KzT3pmOgeyEjnVVerd3JjvY550JKuqdSWRh0TQ578yFY03wzvyPq/d4Z/4tfaJ3xvX3e2cwMnEHBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwASLkWJYRb/7L96Z7OAu78zZgTHeGUnKCPovdHms13/hzrSA/2Kk4bTz3pm89C7vjCR92p/jnckIDHhnzt42xzsz7o193hmMTNwBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMMFipBhWn5ZneWdCwYh3pmPA/ziSdG4g5J1JZGHRq9K7vTNfzzztnWkfyPbOSImdh0QWI22/Os07M847gZGKOyAAgAkKCABgwruAdu/erVtvvVUlJSUKBALatm1b3PMrV65UIBCI25YsWZKseQEAKcK7gLq7u1VeXq66urpL7rNkyRKdPHkytr3yyiuXNSQAIPV4vwmhqqpKVVVVX7pPKBRSUVFRwkMBAFLfkLwGVF9fr4KCAk2fPl0PPPCAzpw5c8l9e3t71dnZGbcBAFJf0gtoyZIleumll7Rz507967/+qxoaGlRVVaWBgcHfollbW6twOBzbSktLkz0SAGAESvr3Ad15552xX8+aNUuzZ8/WtGnTVF9fr4ULF160f01NjdatWxf7uLOzkxICgCvAkL8Ne+rUqcrPz1dTU9Ogz4dCIeXm5sZtAIDUN+QFdPz4cZ05c0bFxcVDfSgAwCji/SW4rq6uuLuZ5uZmHTx4UHl5ecrLy9NTTz2l5cuXq6ioSEePHtUjjzyiq6++WosXL07q4ACA0c27gPbv369bbrkl9vHnr9+sWLFCGzdu1KFDh/Tb3/5W7e3tKikp0aJFi/Szn/1MoZD/2lIAgNTlXUALFiyQc+6Sz//+97+/rIGQ2s4VXfrauZSxwV7vTE80wzsjSTlpPcNyrPFp57wzp/r9Xx+NuoB3RpKi8s/NzGrxzvSP9b8ekDpYCw4AYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYCLpP5Ib+DKRvAHvzPWh496ZT3rzvTOSNC6B1bAnZX7mnWkfyPbOdPT7Z8Lp/qtuS1Ikmuad+WxgnHemryjinUHq4A4IAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACRYjxbBKz+3zztSfu3YIJhlcacYZ78wnfRO9Mz3O/69eIguLRpz/oqKSlJ3m/+d0vC/P/zhXnffOIHVwBwQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEi5FiWOXm+C+o+bWMv3lnJqZ3emckqam3yDszoIB3Jpzmvwhn18AY70yignLema6BkHcmN7vHO4PUwR0QAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAEyxGimGVFvRf5HJimv/Cou93T/fOJCqc5r/Aam80wzsTcWnemYzAgHdGktICUf9jBf2PNS6zzzuD1MEdEADABAUEADDhVUC1tbW64YYblJOTo4KCAi1btkyNjY1x+/T09Ki6uloTJkzQuHHjtHz5crW1tSV1aADA6OdVQA0NDaqurtbevXv1zjvvKBKJaNGiReru7o7t89BDD+mtt97SG2+8oYaGBp04cUK333570gcHAIxuXm9C2LFjR9zHmzdvVkFBgQ4cOKD58+ero6NDv/71r7VlyxZ973vfkyRt2rRJ3/jGN7R371595zvfSd7kAIBR7bJeA+ro6JAk5eXlSZIOHDigSCSiysrK2D4zZszQ5MmTtWfPnkE/R29vrzo7O+M2AEDqS7iAotGo1q5dqxtvvFEzZ86UJLW2tiozM1Pjx4+P27ewsFCtra2Dfp7a2lqFw+HYVlpamuhIAIBRJOECqq6u1uHDh/Xqq69e1gA1NTXq6OiIbS0tLZf1+QAAo0NC34i6Zs0avf3229q9e7cmTZoUe7yoqEh9fX1qb2+Puwtqa2tTUVHRoJ8rFAopFAolMgYAYBTzugNyzmnNmjXaunWrdu3apbKysrjn58yZo4yMDO3cuTP2WGNjo44dO6Z58+YlZ2IAQErwugOqrq7Wli1btH37duXk5MRe1wmHw8rKylI4HNZ9992ndevWKS8vT7m5uXrwwQc1b9483gEHAIjjVUAbN26UJC1YsCDu8U2bNmnlypWSpF/+8pcKBoNavny5ent7tXjxYv3qV79KyrAAgNThVUDOffVCkmPGjFFdXZ3q6uoSHgqp63yf/yKcYwL93pkBl9j7azKC/scKBvwXWD03kOmdSWRh0WACi4pK0kACi6UmIpx53jtzdgjmgA3WggMAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmEjoJ6ICierr87/kxgf7hmCSwSWy8nZvAitHZyfwe+px/uculMAK2pIUcWnemZ4EzkNmMLH5kBq4AwIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCxUgxrPrO+S9Y+XF/2DuTk9bjnZGkAQUSyg2HRBYwzRjGxUijbuSeO4xM3AEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwwWKkGFZppzO9MzlB/4VFMwL93hlJCgVcQjlfiSz2maaod6ZjIMs7I0ljgpGEcr7GpvsvsHpmCOaADe6AAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmGAxUgyr9PPDc5yIS+zSzpD/IqY9LsM7Mybgv9jnxPSz3pmeiP9sktQRzfbO9Eb9z3kw4L/AKlIHd0AAABMUEADAhFcB1dbW6oYbblBOTo4KCgq0bNkyNTY2xu2zYMECBQKBuO3+++9P6tAAgNHPq4AaGhpUXV2tvXv36p133lEkEtGiRYvU3d0dt9+qVat08uTJ2LZhw4akDg0AGP28XjXcsWNH3MebN29WQUGBDhw4oPnz58cez87OVlFRUXImBACkpMt6Daijo0OSlJeXF/f4yy+/rPz8fM2cOVM1NTU6d+7cJT9Hb2+vOjs74zYAQOpL+G3Y0WhUa9eu1Y033qiZM2fGHr/77rs1ZcoUlZSU6NChQ3r00UfV2NioN998c9DPU1tbq6eeeirRMQAAo1TCBVRdXa3Dhw/r/fffj3t89erVsV/PmjVLxcXFWrhwoY4ePapp06Zd9Hlqamq0bt262MednZ0qLS1NdCwAwCiRUAGtWbNGb7/9tnbv3q1JkyZ96b4VFRWSpKampkELKBQKKRQKJTIGAGAU8yog55wefPBBbd26VfX19SorK/vKzMGDByVJxcXFCQ0IAEhNXgVUXV2tLVu2aPv27crJyVFra6skKRwOKysrS0ePHtWWLVv0/e9/XxMmTNChQ4f00EMPaf78+Zo9e/aQ/AYAAKOTVwFt3LhR0oVvNv1HmzZt0sqVK5WZmal3331Xzz33nLq7u1VaWqrly5frscceS9rAAIDU4P0luC9TWlqqhoaGyxoIAHBlYDVsDKvcv/pnMuW/YvKUzE/9DyQpN9jjnVmQ5T/f8f4u70xhWpZ35m/Rk94ZSfq4P9M70xKZ4J15+7Ny7wxSB4uRAgBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMMFipBhWE3/f7J05+L/8f0R7XdMC74wkpb+c553Je/+4d8ZlJfBTgNP8/78Y6Oz2P84w6v/PE9YjwBB3QAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwMeLWgnPOSZL6FZGc8TBIvmifd+R8V793ZuBcr3dGkgKRHu9Mf9T/WG7AO6JE/r8YSGC24dTvItYjYAj068Kf6+f/nl9KwH3VHsPs+PHjKi31X3wSADCytLS0aNKkSZd8fsQVUDQa1YkTJ5STk6NAIBD3XGdnp0pLS9XS0qLc3FyjCe1xHi7gPFzAebiA83DBSDgPzjmdPXtWJSUlCgYvfec+4r4EFwwGv7QxJSk3N/eKvsA+x3m4gPNwAefhAs7DBdbnIRwOf+U+vAkBAGCCAgIAmBhVBRQKhbR+/XqFQgn8NMkUwnm4gPNwAefhAs7DBaPpPIy4NyEAAK4Mo+oOCACQOiggAIAJCggAYIICAgCYGDUFVFdXp69//esaM2aMKioq9Kc//cl6pGH35JNPKhAIxG0zZsywHmvI7d69W7feeqtKSkoUCAS0bdu2uOedc3riiSdUXFysrKwsVVZW6siRIzbDDqGvOg8rV6686PpYsmSJzbBDpLa2VjfccINycnJUUFCgZcuWqbGxMW6fnp4eVVdXa8KECRo3bpyWL1+utrY2o4mHxj9zHhYsWHDR9XD//fcbTTy4UVFAr732mtatW6f169frgw8+UHl5uRYvXqxTp05ZjzbsrrvuOp08eTK2vf/++9YjDbnu7m6Vl5errq5u0Oc3bNig559/Xi+++KL27dunsWPHavHixerp8V9YdCT7qvMgSUuWLIm7Pl555ZVhnHDoNTQ0qLq6Wnv37tU777yjSCSiRYsWqbu7O7bPQw89pLfeektvvPGGGhoadOLECd1+++2GUyffP3MeJGnVqlVx18OGDRuMJr4ENwrMnTvXVVdXxz4eGBhwJSUlrra21nCq4bd+/XpXXl5uPYYpSW7r1q2xj6PRqCsqKnLPPPNM7LH29nYXCoXcK6+8YjDh8PjieXDOuRUrVrilS5eazGPl1KlTTpJraGhwzl34s8/IyHBvvPFGbJ+PPvrISXJ79uyxGnPIffE8OOfcd7/7XfejH/3Ibqh/woi/A+rr69OBAwdUWVkZeywYDKqyslJ79uwxnMzGkSNHVFJSoqlTp+qee+7RsWPHrEcy1dzcrNbW1rjrIxwOq6Ki4oq8Purr61VQUKDp06frgQce0JkzZ6xHGlIdHR2SpLy8PEnSgQMHFIlE4q6HGTNmaPLkySl9PXzxPHzu5ZdfVn5+vmbOnKmamhqdO3fOYrxLGnGLkX7R6dOnNTAwoMLCwrjHCwsL9Ze//MVoKhsVFRXavHmzpk+frpMnT+qpp57SzTffrMOHDysnJ8d6PBOtra2SNOj18flzV4olS5bo9ttvV1lZmY4ePaqf/vSnqqqq0p49e5SWlmY9XtJFo1GtXbtWN954o2bOnCnpwvWQmZmp8ePHx+2bytfDYOdBku6++25NmTJFJSUlOnTokB599FE1NjbqzTffNJw23ogvIPxdVVVV7NezZ89WRUWFpkyZotdff1333Xef4WQYCe68887Yr2fNmqXZs2dr2rRpqq+v18KFCw0nGxrV1dU6fPjwFfE66Je51HlYvXp17NezZs1ScXGxFi5cqKNHj2ratGnDPeagRvyX4PLz85WWlnbRu1ja2tpUVFRkNNXIMH78eF177bVqamqyHsXM59cA18fFpk6dqvz8/JS8PtasWaO3335b7733XtyPbykqKlJfX5/a29vj9k/V6+FS52EwFRUVkjSirocRX0CZmZmaM2eOdu7cGXssGo1q586dmjdvnuFk9rq6unT06FEVFxdbj2KmrKxMRUVFcddHZ2en9u3bd8VfH8ePH9eZM2dS6vpwzmnNmjXaunWrdu3apbKysrjn58yZo4yMjLjrobGxUceOHUup6+GrzsNgDh48KEkj63qwfhfEP+PVV191oVDIbd682f35z392q1evduPHj3etra3Wow2rH//4x66+vt41Nze7P/zhD66ystLl5+e7U6dOWY82pM6ePes+/PBD9+GHHzpJ7tlnn3Uffvih++STT5xzzv3iF79w48ePd9u3b3eHDh1yS5cudWVlZe78+fPGkyfXl52Hs2fPuocfftjt2bPHNTc3u3fffdd961vfctdcc43r6emxHj1pHnjgARcOh119fb07efJkbDt37lxsn/vvv99NnjzZ7dq1y+3fv9/NmzfPzZs3z3Dq5Puq89DU1OSefvppt3//ftfc3Oy2b9/upk6d6ubPn288ebxRUUDOOffCCy+4yZMnu8zMTDd37ly3d+9e65GG3R133OGKi4tdZmam+9rXvubuuOMO19TUZD3WkHvvvfecpIu2FStWOOcuvBX78ccfd4WFhS4UCrmFCxe6xsZG26GHwJedh3PnzrlFixa5iRMnuoyMDDdlyhS3atWqlPtP2mC/f0lu06ZNsX3Onz/vfvjDH7qrrrrKZWdnu9tuu82dPHnSbugh8FXn4dixY27+/PkuLy/PhUIhd/XVV7uf/OQnrqOjw3bwL+DHMQAATIz414AAAKmJAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACAif8H8OZooPKJKDYAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "#load the actual hackthon data (fashion-mnist)\n", - "images=np.load('data/images.npy')\n", - "labels=np.load('data/labels.npy')\n", - "#you can visualize it\n", - "import matplotlib.pyplot as plt\n", - "plt.imshow(images[1100])" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "cb2031cd", - "metadata": {}, - "outputs": [], - "source": [ - "#submission to part 1, you should make this into a .py file\n", - "\n", - "n=len(dataset)\n", - "mse=0\n", - "gatecount=0\n", - "\n", - "def encode(image):\n", - " circuit=cirq.Circuit()\n", - " if image[0][0]==0:\n", - " circuit.append(cirq.rx(np.pi).on(cirq.LineQubit(0)))\n", - " return circuit\n", - "\n", - "def decode(histogram):\n", - " if 1 in histogram.keys():\n", - " image=[[0,0],[0,0]]\n", - " else:\n", - " image=[[1,1],[1,1]]\n", - " return image\n", - "\n", - "def run_part1(image):\n", - " #encode image into a circuit\n", - " circuit=encode(data['image'])\n", - "\n", - " #simulate circuit\n", - " histogram=simulate(circuit)\n", - "\n", - " #reconstruct the image\n", - " image_re=decode(histogram)\n", - "\n", - " return circuit,image_re" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "385faa44", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.0\n" - ] - } - ], - "source": [ - "#how we grade your submission\n", - "\n", - "n=len(dataset)\n", - "mse=0\n", - "gatecount=0\n", - "\n", - "for data in dataset:\n", - " #encode image into circuit\n", - " circuit,image_re=run_part1(data['image'])\n", - " \n", - " #count the number of 2qubit gates used\n", - " gatecount+=count_gates(circuit)[2]\n", - " \n", - " #calculate mse\n", - " mse+=image_mse(data['image'],image_re)\n", - " \n", - "#fidelity of reconstruction\n", - "f=1-mse\n", - "gatecount=gatecount/n\n", - "\n", - "#score for part1 \n", - "print(f*(0.999**gatecount))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ad7e81d7", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/.ipynb_checkpoints/part2_example_cirq-checkpoint.ipynb b/.ipynb_checkpoints/part2_example_cirq-checkpoint.ipynb deleted file mode 100644 index 2bb7a6d..0000000 --- a/.ipynb_checkpoints/part2_example_cirq-checkpoint.ipynb +++ /dev/null @@ -1,221 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "id": "5519a2aa", - "metadata": {}, - "outputs": [], - "source": [ - "import cirq\n", - "import numpy as np\n", - "import pickle\n", - "import json\n", - "import os\n", - "from collections import Counter\n", - "from sklearn.metrics import mean_squared_error\n", - "\n", - "#define utility functions\n", - "\n", - "def simulate(circuit: cirq.Circuit) -> dict:\n", - " \"\"\"This funcion simulate a cirq circuit (without measurement) and output results in the format of histogram.\n", - " \"\"\"\n", - " simulator = cirq.Simulator()\n", - " result = simulator.simulate(circuit)\n", - " \n", - " state_vector=result.final_state_vector\n", - " \n", - " histogram = dict()\n", - " for i in range(len(state_vector)):\n", - " population = abs(state_vector[i]) ** 2\n", - " if population > 1e-9:\n", - " histogram[i] = population\n", - " \n", - " return histogram\n", - "\n", - "\n", - "def histogram_to_category(histogram):\n", - " \"\"\"This function take a histogram representations of circuit execution results, and process into labels as described in \n", - " the problem description.\"\"\"\n", - " assert abs(sum(histogram.values())-1)<1e-8\n", - " positive=0\n", - " for key in histogram.keys():\n", - " digits = bin(int(key))[2:].zfill(20)\n", - " if digits[-1]=='0':\n", - " positive+=histogram[key]\n", - " \n", - " return positive\n", - "\n", - "def count_gates(circuit: cirq.Circuit):\n", - " \"\"\"Returns the number of 1-qubit gates, number of 2-qubit gates, number of 3-qubit gates....\"\"\"\n", - " counter=Counter([len(op.qubits) for op in circuit.all_operations()])\n", - " \n", - " #feel free to comment out the following two lines. But make sure you don't have k-qubit gates in your circuit\n", - " #for k>2\n", - " for i in range(2,20):\n", - " assert counter[i]==0\n", - " \n", - " return counter\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "11a77286", - "metadata": {}, - "outputs": [], - "source": [ - "#load the mock data (for testing only)\n", - "files=os.listdir(\"mock_data\")\n", - "dataset=list()\n", - "for file in files:\n", - " with open('mock_data/'+file, \"r\") as infile:\n", - " loaded = json.load(infile)\n", - " dataset.append(loaded)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "dfbb6735", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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TL/2P70zzjuBVMJacAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEwM+Q+kA/7R+JXd3pn2P2R5Z8YEI94ZSerq9//hiFOz/BdY/ai7xDuTHvRfKHU4F2X9j48meWeukf8Cpkgd3AEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEywGjaGVX9rm3fmd+3l3pmbc//DOyNJ//aZ/7FOR3K8M1OyTntnWnvD3pmoC3hnLuT8/29aXJ/QoXAF4w4IAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACRYjxYjXHsn2zpSmf5bQsW7IbfbO/PlcSULH8jUuvdc7E4mmJXSsnmiGdybnr13eGeedQCrhDggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJFiPFiPf+J1O9M3fk70voWH/rH+uduX7sMe9MIot9JiLiEvsrfrp/nHcmeD7inRnwTiCVcAcEADBBAQEATHgX0O7du3XrrbeqpKREgUBA27Zti3veOacnnnhCxcXFysrKUmVlpY4cOZKseQEAKcK7gLq7u1VeXq66urpBn9+wYYOef/55vfjii9q3b5/Gjh2rxYsXq6en57KHBQCkDu9XKKuqqlRVVTXoc845Pffcc3rssce0dOlSSdJLL72kwsJCbdu2TXfeeeflTQsASBlJfQ2oublZra2tqqysjD0WDodVUVGhPXv2DJrp7e1VZ2dn3AYASH1JLaDW1lZJUmFhYdzjhYWFsee+qLa2VuFwOLaVlpYmcyQAwAhl/i64mpoadXR0xLaWlhbrkQAAwyCpBVRUVCRJamtri3u8ra0t9twXhUIh5ebmxm0AgNSX1AIqKytTUVGRdu7cGXuss7NT+/bt07x585J5KADAKOf9Lriuri41NTXFPm5ubtbBgweVl5enyZMna+3atfr5z3+ua665RmVlZXr88cdVUlKiZcuWJXNuAMAo511A+/fv1y233BL7eN26dZKkFStWaPPmzXrkkUfU3d2t1atXq729XTfddJN27NihMWPGJG9qAMCo511ACxYskHPuks8HAgE9/fTTevrppy9rMOBzkR7/BTV7XGKLfUZcmndmwA3Pe3kyAv5Ld44J+i8QKkklGX/zzuzLuj6hY+HKZf4uOADAlYkCAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYMJ/mWFgmP2Xb3zknfm0P7GfrJvIathtkbB3piTTf7XpMQH/la1bInneGUnKC3V5Z9qe8F+tu2CpdwQphDsgAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJliMFCPe1KzT3pmOgeyEjnVVerd3JjvY550JKuqdSWRh0TQ578yFY03wzvyPq/d4Z/4tfaJ3xvX3e2cwMnEHBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwASLkWJYRb/7L96Z7OAu78zZgTHeGUnKCPovdHms13/hzrSA/2Kk4bTz3pm89C7vjCR92p/jnckIDHhnzt42xzsz7o193hmMTNwBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMMFipBhWn5ZneWdCwYh3pmPA/ziSdG4g5J1JZGHRq9K7vTNfzzztnWkfyPbOSImdh0QWI22/Os07M847gZGKOyAAgAkKCABgwruAdu/erVtvvVUlJSUKBALatm1b3PMrV65UIBCI25YsWZKseQEAKcK7gLq7u1VeXq66urpL7rNkyRKdPHkytr3yyiuXNSQAIPV4vwmhqqpKVVVVX7pPKBRSUVFRwkMBAFLfkLwGVF9fr4KCAk2fPl0PPPCAzpw5c8l9e3t71dnZGbcBAFJf0gtoyZIleumll7Rz507967/+qxoaGlRVVaWBgcHfollbW6twOBzbSktLkz0SAGAESvr3Ad15552xX8+aNUuzZ8/WtGnTVF9fr4ULF160f01NjdatWxf7uLOzkxICgCvAkL8Ne+rUqcrPz1dTU9Ogz4dCIeXm5sZtAIDUN+QFdPz4cZ05c0bFxcVDfSgAwCji/SW4rq6uuLuZ5uZmHTx4UHl5ecrLy9NTTz2l5cuXq6ioSEePHtUjjzyiq6++WosXL07q4ACA0c27gPbv369bbrkl9vHnr9+sWLFCGzdu1KFDh/Tb3/5W7e3tKikp0aJFi/Szn/1MoZD/2lIAgNTlXUALFiyQc+6Sz//+97+/rIGQ2s4VXfrauZSxwV7vTE80wzsjSTlpPcNyrPFp57wzp/r9Xx+NuoB3RpKi8s/NzGrxzvSP9b8ekDpYCw4AYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYCLpP5Ib+DKRvAHvzPWh496ZT3rzvTOSNC6B1bAnZX7mnWkfyPbOdPT7Z8Lp/qtuS1Ikmuad+WxgnHemryjinUHq4A4IAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACRYjxbBKz+3zztSfu3YIJhlcacYZ78wnfRO9Mz3O/69eIguLRpz/oqKSlJ3m/+d0vC/P/zhXnffOIHVwBwQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEi5FiWOXm+C+o+bWMv3lnJqZ3emckqam3yDszoIB3Jpzmvwhn18AY70yignLema6BkHcmN7vHO4PUwR0QAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAEyxGimGVFvRf5HJimv/Cou93T/fOJCqc5r/Aam80wzsTcWnemYzAgHdGktICUf9jBf2PNS6zzzuD1MEdEADABAUEADDhVUC1tbW64YYblJOTo4KCAi1btkyNjY1x+/T09Ki6uloTJkzQuHHjtHz5crW1tSV1aADA6OdVQA0NDaqurtbevXv1zjvvKBKJaNGiReru7o7t89BDD+mtt97SG2+8oYaGBp04cUK333570gcHAIxuXm9C2LFjR9zHmzdvVkFBgQ4cOKD58+ero6NDv/71r7VlyxZ973vfkyRt2rRJ3/jGN7R371595zvfSd7kAIBR7bJeA+ro6JAk5eXlSZIOHDigSCSiysrK2D4zZszQ5MmTtWfPnkE/R29vrzo7O+M2AEDqS7iAotGo1q5dqxtvvFEzZ86UJLW2tiozM1Pjx4+P27ewsFCtra2Dfp7a2lqFw+HYVlpamuhIAIBRJOECqq6u1uHDh/Xqq69e1gA1NTXq6OiIbS0tLZf1+QAAo0NC34i6Zs0avf3229q9e7cmTZoUe7yoqEh9fX1qb2+Puwtqa2tTUVHRoJ8rFAopFAolMgYAYBTzugNyzmnNmjXaunWrdu3apbKysrjn58yZo4yMDO3cuTP2WGNjo44dO6Z58+YlZ2IAQErwugOqrq7Wli1btH37duXk5MRe1wmHw8rKylI4HNZ9992ndevWKS8vT7m5uXrwwQc1b9483gEHAIjjVUAbN26UJC1YsCDu8U2bNmnlypWSpF/+8pcKBoNavny5ent7tXjxYv3qV79KyrAAgNThVUDOffVCkmPGjFFdXZ3q6uoSHgqp63yf/yKcYwL93pkBl9j7azKC/scKBvwXWD03kOmdSWRh0WACi4pK0kACi6UmIpx53jtzdgjmgA3WggMAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmEjoJ6ICierr87/kxgf7hmCSwSWy8nZvAitHZyfwe+px/uculMAK2pIUcWnemZ4EzkNmMLH5kBq4AwIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCxUgxrPrO+S9Y+XF/2DuTk9bjnZGkAQUSyg2HRBYwzRjGxUijbuSeO4xM3AEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwwWKkGFZppzO9MzlB/4VFMwL93hlJCgVcQjlfiSz2maaod6ZjIMs7I0ljgpGEcr7GpvsvsHpmCOaADe6AAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmGAxUgyr9PPDc5yIS+zSzpD/IqY9LsM7Mybgv9jnxPSz3pmeiP9sktQRzfbO9Eb9z3kw4L/AKlIHd0AAABMUEADAhFcB1dbW6oYbblBOTo4KCgq0bNkyNTY2xu2zYMECBQKBuO3+++9P6tAAgNHPq4AaGhpUXV2tvXv36p133lEkEtGiRYvU3d0dt9+qVat08uTJ2LZhw4akDg0AGP28XjXcsWNH3MebN29WQUGBDhw4oPnz58cez87OVlFRUXImBACkpMt6Daijo0OSlJeXF/f4yy+/rPz8fM2cOVM1NTU6d+7cJT9Hb2+vOjs74zYAQOpL+G3Y0WhUa9eu1Y033qiZM2fGHr/77rs1ZcoUlZSU6NChQ3r00UfV2NioN998c9DPU1tbq6eeeirRMQAAo1TCBVRdXa3Dhw/r/fffj3t89erVsV/PmjVLxcXFWrhwoY4ePapp06Zd9Hlqamq0bt262MednZ0qLS1NdCwAwCiRUAGtWbNGb7/9tnbv3q1JkyZ96b4VFRWSpKampkELKBQKKRQKJTIGAGAU8yog55wefPBBbd26VfX19SorK/vKzMGDByVJxcXFCQ0IAEhNXgVUXV2tLVu2aPv27crJyVFra6skKRwOKysrS0ePHtWWLVv0/e9/XxMmTNChQ4f00EMPaf78+Zo9e/aQ/AYAAKOTVwFt3LhR0oVvNv1HmzZt0sqVK5WZmal3331Xzz33nLq7u1VaWqrly5frscceS9rAAIDU4P0luC9TWlqqhoaGyxoIAHBlYDVsDKvcv/pnMuW/YvKUzE/9DyQpN9jjnVmQ5T/f8f4u70xhWpZ35m/Rk94ZSfq4P9M70xKZ4J15+7Ny7wxSB4uRAgBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMMFipBhWE3/f7J05+L/8f0R7XdMC74wkpb+c553Je/+4d8ZlJfBTgNP8/78Y6Oz2P84w6v/PE9YjwBB3QAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwMeLWgnPOSZL6FZGc8TBIvmifd+R8V793ZuBcr3dGkgKRHu9Mf9T/WG7AO6JE/r8YSGC24dTvItYjYAj068Kf6+f/nl9KwH3VHsPs+PHjKi31X3wSADCytLS0aNKkSZd8fsQVUDQa1YkTJ5STk6NAIBD3XGdnp0pLS9XS0qLc3FyjCe1xHi7gPFzAebiA83DBSDgPzjmdPXtWJSUlCgYvfec+4r4EFwwGv7QxJSk3N/eKvsA+x3m4gPNwAefhAs7DBdbnIRwOf+U+vAkBAGCCAgIAmBhVBRQKhbR+/XqFQgn8NMkUwnm4gPNwAefhAs7DBaPpPIy4NyEAAK4Mo+oOCACQOiggAIAJCggAYIICAgCYGDUFVFdXp69//esaM2aMKioq9Kc//cl6pGH35JNPKhAIxG0zZsywHmvI7d69W7feeqtKSkoUCAS0bdu2uOedc3riiSdUXFysrKwsVVZW6siRIzbDDqGvOg8rV6686PpYsmSJzbBDpLa2VjfccINycnJUUFCgZcuWqbGxMW6fnp4eVVdXa8KECRo3bpyWL1+utrY2o4mHxj9zHhYsWHDR9XD//fcbTTy4UVFAr732mtatW6f169frgw8+UHl5uRYvXqxTp05ZjzbsrrvuOp08eTK2vf/++9YjDbnu7m6Vl5errq5u0Oc3bNig559/Xi+++KL27dunsWPHavHixerp8V9YdCT7qvMgSUuWLIm7Pl555ZVhnHDoNTQ0qLq6Wnv37tU777yjSCSiRYsWqbu7O7bPQw89pLfeektvvPGGGhoadOLECd1+++2GUyffP3MeJGnVqlVx18OGDRuMJr4ENwrMnTvXVVdXxz4eGBhwJSUlrra21nCq4bd+/XpXXl5uPYYpSW7r1q2xj6PRqCsqKnLPPPNM7LH29nYXCoXcK6+8YjDh8PjieXDOuRUrVrilS5eazGPl1KlTTpJraGhwzl34s8/IyHBvvPFGbJ+PPvrISXJ79uyxGnPIffE8OOfcd7/7XfejH/3Ibqh/woi/A+rr69OBAwdUWVkZeywYDKqyslJ79uwxnMzGkSNHVFJSoqlTp+qee+7RsWPHrEcy1dzcrNbW1rjrIxwOq6Ki4oq8Purr61VQUKDp06frgQce0JkzZ6xHGlIdHR2SpLy8PEnSgQMHFIlE4q6HGTNmaPLkySl9PXzxPHzu5ZdfVn5+vmbOnKmamhqdO3fOYrxLGnGLkX7R6dOnNTAwoMLCwrjHCwsL9Ze//MVoKhsVFRXavHmzpk+frpMnT+qpp57SzTffrMOHDysnJ8d6PBOtra2SNOj18flzV4olS5bo9ttvV1lZmY4ePaqf/vSnqqqq0p49e5SWlmY9XtJFo1GtXbtWN954o2bOnCnpwvWQmZmp8ePHx+2bytfDYOdBku6++25NmTJFJSUlOnTokB599FE1NjbqzTffNJw23ogvIPxdVVVV7NezZ89WRUWFpkyZotdff1333Xef4WQYCe68887Yr2fNmqXZs2dr2rRpqq+v18KFCw0nGxrV1dU6fPjwFfE66Je51HlYvXp17NezZs1ScXGxFi5cqKNHj2ratGnDPeagRvyX4PLz85WWlnbRu1ja2tpUVFRkNNXIMH78eF177bVqamqyHsXM59cA18fFpk6dqvz8/JS8PtasWaO3335b7733XtyPbykqKlJfX5/a29vj9k/V6+FS52EwFRUVkjSirocRX0CZmZmaM2eOdu7cGXssGo1q586dmjdvnuFk9rq6unT06FEVFxdbj2KmrKxMRUVFcddHZ2en9u3bd8VfH8ePH9eZM2dS6vpwzmnNmjXaunWrdu3apbKysrjn58yZo4yMjLjrobGxUceOHUup6+GrzsNgDh48KEkj63qwfhfEP+PVV191oVDIbd682f35z392q1evduPHj3etra3Wow2rH//4x66+vt41Nze7P/zhD66ystLl5+e7U6dOWY82pM6ePes+/PBD9+GHHzpJ7tlnn3Uffvih++STT5xzzv3iF79w48ePd9u3b3eHDh1yS5cudWVlZe78+fPGkyfXl52Hs2fPuocfftjt2bPHNTc3u3fffdd961vfctdcc43r6emxHj1pHnjgARcOh119fb07efJkbDt37lxsn/vvv99NnjzZ7dq1y+3fv9/NmzfPzZs3z3Dq5Puq89DU1OSefvppt3//ftfc3Oy2b9/upk6d6ubPn288ebxRUUDOOffCCy+4yZMnu8zMTDd37ly3d+9e65GG3R133OGKi4tdZmam+9rXvubuuOMO19TUZD3WkHvvvfecpIu2FStWOOcuvBX78ccfd4WFhS4UCrmFCxe6xsZG26GHwJedh3PnzrlFixa5iRMnuoyMDDdlyhS3atWqlPtP2mC/f0lu06ZNsX3Onz/vfvjDH7qrrrrKZWdnu9tuu82dPHnSbugh8FXn4dixY27+/PkuLy/PhUIhd/XVV7uf/OQnrqOjw3bwL+DHMQAATIz414AAAKmJAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACAif8H8OZooPKJKDYAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "#load the actual hackthon data (fashion-mnist)\n", - "images=np.load('data/images.npy')\n", - "labels=np.load('data/labels.npy')\n", - "#you can visualize it\n", - "import matplotlib.pyplot as plt\n", - "plt.imshow(images[1100])" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "66e9a047", - "metadata": {}, - "outputs": [], - "source": [ - "#you submission\n", - "\n", - "def encode(image):\n", - " circuit=cirq.Circuit()\n", - " if image[0][0]==0:\n", - " circuit.append(cirq.rx(np.pi).on(cirq.LineQubit(0)))\n", - " return circuit\n", - "\n", - "\n", - "def run_part2(image):\n", - "\n", - " #loade the quantum classifier circuit\n", - " with open('part2.pickle', 'rb') as f:\n", - " classifier=pickle.load(f)\n", - " \n", - " #encode image into circuit\n", - " circuit=encode(image)\n", - " \n", - " #append with classifier circuit\n", - " \n", - " circuit.append(classifier)\n", - " \n", - " #simulate circuit\n", - " histogram=simulate(circuit)\n", - " \n", - " #convert histogram to category\n", - " label=histogram_to_category(histogram)\n", - " \n", - " return circuit,label\n", - "#score" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "18e6015f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.0\n" - ] - } - ], - "source": [ - "#how we grade your submission\n", - "\n", - "score=0\n", - "gatecount=0\n", - "n=len(dataset)\n", - "\n", - "for data in dataset:\n", - " #run part 2\n", - " circuit,label=run_part2(data['image'])\n", - " \n", - " #count the gate used in the circuit for score calculation\n", - " gatecount+=count_gates(circuit)[2]\n", - " \n", - " #check label\n", - " if label==data['category']:\n", - " score+=1\n", - "#score\n", - "score=score/n\n", - "gatecount=gatecount/n\n", - "\n", - "print(score*(0.999**gatecount))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a73d2810", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/__pycache__/part1.cpython-38.pyc b/__pycache__/part1.cpython-38.pyc deleted file mode 100644 index 606d227..0000000 Binary files a/__pycache__/part1.cpython-38.pyc and /dev/null differ diff --git a/__pycache__/part1.cpython-39.pyc b/__pycache__/part1.cpython-39.pyc deleted file mode 100644 index 9e215d2..0000000 Binary files a/__pycache__/part1.cpython-39.pyc and /dev/null differ diff --git a/compare_images_terminal_part1.py b/compare_images_terminal_part1.py new file mode 100644 index 0000000..1ea7099 --- /dev/null +++ b/compare_images_terminal_part1.py @@ -0,0 +1,58 @@ +import numpy as np + +from part1 import load_images, run_part1 + +images = load_images("data/images.npy") + + +def value_to_text(value: int) -> str: + """Divide the 0-255 interval in 5 parts using , ░░, ▒▒, ▓▓and ██""" + if value < 51: + return " " + elif value < 102: + return "░░" + elif value < 153: + return "▒▒" + elif value < 204: + return "▓▓" + elif value < 256: + return "██" + + +def display_images(left_image, right_image): + print("") + for i in range(left_image.shape[0]): + for j in range(left_image.shape[0]): + print(value_to_text(left_image[i][j]), end="") + + print(" ", end="") + for j in range(left_image.shape[0]): + try: + print(value_to_text(right_image[i][j]), end="") + except IndexError: + print("", end="") + break + print("") + + print("\n" + "Before".center(left_image.shape[0] * 2) + " " + "After".center(left_image.shape[0] * 2)) + + +# update the images based on the entered number +num = int(input("Enter the number of the image you want to display: ")) + +try: + left_image = images[int(num)] +except IndexError: + left_image = np.ones((28, 28)) * 255 + + +print(f"Computing for image n° {int(num)}...\n") + +right_image = run_part1(left_image)[1] + +print("Computing done!") + +display_images(left_image, right_image) + +print(left_image) +print(right_image) \ No newline at end of file diff --git a/compare_images_tkinter_part1.py b/compare_images_tkinter_part1.py new file mode 100644 index 0000000..510210d --- /dev/null +++ b/compare_images_tkinter_part1.py @@ -0,0 +1,87 @@ +import tkinter as tk +from PIL import Image, ImageTk +import numpy as np +from pprint import pprint + +from part1 import load_images, run_part1 + +images = load_images("data/images.npy") + + +def update_images(num): + global left_image, right_image, left_photo, right_photo, left_label, right_label, status_label + + try: + left_image = images[int(num)] + except IndexError: + left_image = np.ones((28, 28)) * 255 + + # update the images based on the entered number + print(f"Computing for image n° {int(num)}...") + right_image = run_part1(left_image)[1] + print("Right : ") + pprint(left_image) + print("Left : ") + pprint(right_image) + status_label.configure(text=f"Image n° {int(num)}") + + # right_image = np.random.randint(0, 255, (28, 28)) + + left_photo = ImageTk.PhotoImage( + Image.fromarray(left_image).resize((280, 280), Image.BOX) + ) + right_photo = ImageTk.PhotoImage( + Image.fromarray(right_image).resize((280, 280), Image.BOX) + ) + left_label.configure(image=left_photo) + right_label.configure(image=right_photo) + + +# Create the main window +root = tk.Tk() +root.title("Image Viewer") + +# Create the left image +left_image = images[0] +left_photo = ImageTk.PhotoImage( + Image.fromarray(left_image).resize((280, 280), Image.BOX) +) + +# Create the right image +right_image = np.random.randint(0, 255, (28, 28)) +right_photo = ImageTk.PhotoImage( + Image.fromarray(right_image).resize((280, 280), Image.BOX) +) + +# Create the left image label and add it to the main window +left_label = tk.Label(root, image=left_photo) +left_label.grid(row=0, column=0) + +# Create the right image label and add it to the main window +right_label = tk.Label(root, image=right_photo) +right_label.grid(row=0, column=1) + +# Status label +status_label = tk.Label(root, text="Image n° 0") +status_label.grid(row=1, column=0, columnspan=2) + +# Create a label for the number prompt +prompt_label = tk.Label(root, text="Enter a number:") +prompt_label.grid(row=2, column=0, columnspan=2) + +# Create an entry widget for the number prompt +number_entry = tk.Entry(root) +number_entry.grid(row=3, column=0, columnspan=2) + +# Create a button to update the images +update_button = tk.Button( + root, text="Update Images", command=lambda: update_images(number_entry.get()) +) +update_button.grid(row=34, column=0, columnspan=2) + +root.bind("", lambda e: update_images(number_entry.get())) + +root.bind("", lambda e: root.destroy()) + +# Run the main loop +root.mainloop() diff --git a/part1.py b/part1.py index d133097..1bfde36 100644 --- a/part1.py +++ b/part1.py @@ -1,25 +1,258 @@ -import cirq +from collections import Counter import qiskit +from qiskit import Aer +import qiskit.circuit.library +from qiskit import transpile, assemble +from qiskit.visualization import plot_histogram +from qiskit.circuit.library import RYGate + +from matplotlib import pyplot as plt + import numpy as np +import math +from pprint import pprint +from typing import Dict, Union -def encode_cirq(image): - circuit=cirq.Circuit() - if image[0][0]==0: - circuit.append(cirq.rx(np.pi).on(cirq.LineQubit(0))) - return circuit +from sklearn.metrics import mean_squared_error -def encode_qiskit(image): - q = qiskit.QuantumRegister(3) - circuit = qiskit.QuantumCircuit(q) - if image[0][0]==0: - circuit.rx(np.pi,0) - return circuit +# Image properties +SIZE = 28 # Image width +NB_PX_IMG = SIZE ** 2 + +# quantum parameters +N = math.ceil(math.log2(SIZE)) +NB_QUBITS = 2 * N + 1 +NB_PX = 2 ** (2 * N) + +def load_images(path: str) -> np.ndarray: + images = np.load(path) + images = images / max(images.flatten()) * 255 + return images + + +def pixel_value_to_theta(pixel: float) -> float: + return pixel / 255 * (np.pi / 2) + + +def theta_to_pixel_value(theta: float) -> int: + return int(theta / (np.pi / 2) * 255) + + +def get_proba(counts: dict) -> dict: + sums = sum(map(lambda x: x[1], counts.items())) + return {key: value / sums for key, value in counts.items()} + + +def encode(image: np.ndarray) -> qiskit.QuantumCircuit: + circuit = qiskit.QuantumCircuit(NB_QUBITS) + + # Get the theta values for each pixel + image = image.flatten() + thetas = [pixel_value_to_theta(pixel) for pixel in image] + thetas += [0] * (NB_PX - NB_PX_IMG) + + # Apply Hadamard gates for all qubits except the last one + for i in range(NB_QUBITS - 1): + circuit.h(i) + #circuit.barrier() + + ry_qbits = list(range(NB_QUBITS)) + + # Switch is no longer relevant written this way: instead, we should apply the X gates according to + # the result of process_image (see above) + # intensity_count_expression = process_image(image) + # switches = [ice[2][i] ^ ice[2][i-1] for i in range(intensity_count_expression)] + # This also means that an optimisation has to be done to minimise the number of X gates applied + # (XOR yielding minimal number of 1s) + switches = [bin(0)[2:].zfill(NB_QUBITS - 1)] + [ + bin(i ^ (i - 1))[2:].zfill(NB_QUBITS - 1) for i in range(1, NB_PX) + ] + + # TODO remove switches which is not used anymore + + # Apply the rotation gates + prev_switch = switches[0] + for i in range(NB_PX): + theta = thetas[i] # pixel_value_to_theta(intensity_count_expression[i][0]) + + # do not do zero rotation + if theta != 0: + switch = np.binary_repr(i, NB_QUBITS - 1) + + # Apply x gate to the i-th qubit if the i-th bit of the switch is 1 + for j in range(NB_QUBITS - 1): + if switch[j] != prev_switch[j]: + circuit.x(j) + # if switch[j] == "1": + # circuit.x(j - 1) + prev_switch = switch + + # TODO: Not a 2-qubit gate: reformulate using 2-qubit gates only (RYGate + CNOT) + # Instead of 2 * theta, rotation is 2 * count * theta + # where count is stored in intensity_count_expression[1] + # where theta is result of pixel_value_to_theta(intensity_count_expression[0]) + # When simplified expression, control is only on the number of qubits not equal to 2 or - (do not care + + # TODO: Not a 2-qubit gate: reformulate using 2-qubit gates only (RYGate + CNOT) + # Instead of 2 * theta, rotation is 2 * count * theta + # where count is stored in intensity_count_expression[1] + # where theta is result of pixel_value_to_theta(intensity_count_expression[0]) + # When simplified expression, control is only on the number of qubits not equal to 2 or - (do not care) + #c3ry = RYGate(2 * theta).control(NB_QUBITS - 1) # intensity_count_expression[i][1] * 2 * theta + # In this case, ry_qbits is the position of the qubits not equal to 2 or - (do not care) + #circuit.append(c3ry, ry_qbits) + + recursive_ry(circuit, 2*theta, np.array([1]*(NB_QUBITS - 1))) + + #circuit.barrier() + + # check all qbits are at 1 for the measurements + for j in range(NB_QUBITS - 1): + if prev_switch[j] != "1": + circuit.x(j) + + circuit.measure_all() + return circuit -def decode(histogram): - if 1 in histogram.keys(): - image=[[0,0],[0,0]] +def recursive_ry(circuit, theta, mask): + if mask.sum() == 2: + idxs = np.where(mask == 1)[0] + circuit.cry(theta/2, idxs[0], NB_QUBITS - 1) + circuit.cx(idxs[0], idxs[1]) + circuit.cry(-theta/2, idxs[1], NB_QUBITS - 1) + circuit.cx(idxs[0], idxs[1]) + circuit.cry(theta/2, idxs[1], NB_QUBITS - 1) else: - image=[[1,1],[1,1]] - return image \ No newline at end of file + idx1, idx2 = np.where(mask == 1)[0][:2] + + maskn = mask.copy() + maskn[idx2] = 0 + recursive_ry(circuit, theta/2, maskn) + # c3ry = RYGate(theta).control(NB_QUBITS - 1) + # circuit.append(c3ry, ry_qbits) + circuit.cx(idx1, idx2) + + maskn = mask.copy() + maskn[idx1] = 0 + recursive_ry(circuit, -theta/2, maskn) + circuit.cx(idx1, idx2) + + maskn = mask.copy() + maskn[idx1] = 0 + recursive_ry(circuit, theta/2, maskn) + + +def decode(counts: dict) -> np.ndarray: + histogram = get_proba(counts) + img = np.zeros(NB_PX) # we have a square image + + for i in range(NB_PX): + print(i) + bin_str: str = np.binary_repr(i, width=NB_QUBITS - 1) + print(bin_str) + cos_str = "0" + bin_str[::-1] + sin_str = "1" + bin_str[::-1] + + if cos_str in histogram: + prob_cos = histogram[cos_str] + theta = math.acos(np.clip(2**N * math.sqrt(prob_cos), 0, 1)) + else: + prob_cos = 0 + + # not needed? + if sin_str in histogram: + prob_sin = histogram[sin_str] + theta = math.asin(np.clip(2**N * math.sqrt(prob_sin), 0, 1)) + else: + prob_sin = 0 + + img[i] = theta_to_pixel_value(theta) + + img = img[:NB_PX_IMG] + return img.reshape(SIZE, SIZE) + + +def simulator(circuit: qiskit.QuantumCircuit) -> dict: + # Simulate the circuit + aer_sim = Aer.get_backend("aer_simulator") + t_qc = transpile(circuit, aer_sim) + qobj = assemble(t_qc, shots=1024) + + result = aer_sim.run(qobj).result() + return result.get_counts(circuit) + + +def run_part1(image: np.ndarray) -> Union[qiskit.QuantumCircuit, np.ndarray]: + circuit = encode(image) + counts = simulator(circuit) + print(count_gates(circuit)) + print(dict(circuit.count_ops())) + img = decode(counts) + return circuit, img + +def count_gates(circuit: qiskit.QuantumCircuit) -> Dict[int, int]: + """Returns the number of gate operations with each number of qubits.""" + return Counter([len(gate[1]) for gate in circuit.data]) + +def image_mse(image1,image2): + # Using sklearns mean squared error: + # https://scikit-learn.org/stable/modules/generated/sklearn.metrics.mean_squared_error.html + return mean_squared_error(image1, image2) + +def grading(dataset): + n=len(dataset) + mse=0 + gatecount=0 + + for data in dataset: + circuit, image_re = run_part1(data['image']) + # Count 2-qubit gates in circuit + gatecount += count_gates(circuit)[2] + + # Calculate MSE + mse += image_mse(data['image'],image_re) + + # Fidelity of reconstruction + f = 1 - mse + gatecount = gatecount / n + + # Score for Part 1 + return f * (0.999 ** gatecount) + +if __name__ == "__main__": + image = load_images("data/images.npy")[5] + if image.max() != 0: + image = image / image.max() * 255 + # plt.imshow(image, cmap='gray') + # plt.show() + + # print(image) + + #image = np.array([0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 120]) + # image = np.array([128]*16) + #image = image[:NB_PX] + print(image) + + circuit = encode(image) + print(count_gates(circuit)) + + # Simulate the circuit + aer_sim = Aer.get_backend("aer_simulator") + t_qc = transpile(circuit, aer_sim) + qobj = assemble(t_qc, shots=16384) + + result = aer_sim.run(qobj).result() + counts = result.get_counts(circuit) + print(counts) + print(len(counts)) + + # Decode the histogram + img = decode(get_proba(counts)) + img = img.flatten() + print(img.flatten()) + print(img[:28*(len(img) // 28)].reshape(len(img) // 28, 28)) + print(img) + # plt.hist(img.flatten()) + # plt.show() diff --git a/part2.py b/part2.py new file mode 100644 index 0000000..d197aff --- /dev/null +++ b/part2.py @@ -0,0 +1,183 @@ +import numpy as np +import pickle +from collections import Counter +from sklearn.metrics import mean_squared_error +import qiskit +from typing import Union + +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim + +import torch.autograd + +from part1 import encode, simulator + +def histogram_to_category(histogram: dict) -> int: + return 1 + +# def histogram_to_category(histogram: dict) -> int: + # assert abs(sum(histogram.values())-1)<1e-8 + # positive=0 + # for key in histogram.keys(): + # digits = bin(int(key))[2:].zfill(20) + # if digits[-1]=='0': + # positive+=histogram[key] + # return positive + + +def load_qasm(path: str) -> qiskit.QuantumCircuit: + with open(path, 'r') as f: + qasm=f.read() + return qiskit.QuantumCircuit.from_qasm_str(qasm) + + +def split_train_test_data(images: np.ndarray, labels: np.ndarray, train_ratio: float=0.8) -> Union[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: + nb_train = int(len(images)*train_ratio) + train_images = images[:nb_train] + train_labels = labels[:nb_train] + test_images = images[nb_train:] + test_labels = labels[nb_train:] + return train_images, train_labels, test_images, test_labels + +## Classes for the Hybrid (classical + quantum) Classifier [HC] + +# General idea : +# The HC is made of three parts: +# - A classical neural network whose architecture is defined in the ClassicalNet class +# - A quantum circuit whose architecture is defined in the QuantumNet class +# The Quantum Net is parametrised by the weights of the Classical Net +# We also need a forward function that will take the input of the classical net and pass it to the quantum net +# The HybridClassifier class will be the one gluing all the parts together. It will be the one we will train and use to make predictions +class QuantumCircuit: + def __init__(self, circuit: qiskit.QuantumCircuit, backend=qiskit.Aer.get_backend("aer_simulator"), shots: int = 1024): #TODO Typing + # This circuit will be parametrised by the weights of a upstream NN + self.circuit = circuit + self.theta = qiskit.circuit.Parameter('theta') + self.backend = backend + self.shots = shots + + def simulate(self, weights: np.ndarray) -> dict: + t_qc = qiskit.transpile(self.circuit, self.backend) + qobj = qiskit.assemble(t_qc, shots=self.shots, parameter_binds = [{self.theta: weight} for weight in weights]) + job = self.backend.run(qobj) + result = job.result().get_counts(self.circuit) + + counts = np.array(list(result.values())) + states = np.array(list(result.keys())).astype(float) + + return result + + +class ClassicalNet(nn.Module): + def __init__(self): + super(ClassicalNet, self).__init__() + # TODO: Replace with better architecture + self.conv1 = nn.Conv2d(1, 6, kernel_size=5) + self.conv2 = nn.Conv2d(6, 16, kernel_size=5) + self.dropout = nn.Dropout2d() + self.fc1 = nn.Linear(256, 64) + self.fc2 = nn.Linear(64, 1) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = F.relu(self.conv1(x)) + x = F.max_pool2d(x, 2) + x = F.relu(self.conv2(x)) + x = F.max_pool2d(x, 2) + x = self.dropout(x) + x = x.view(1, -1) + x = F.relu(self.fc1(x)) + x = self.fc2(x) + return x + + +class QuantumFunctions(torch.autograd.Function): + @staticmethod + def forward(ctx, circuit: qiskit.QuantumCircuit, x: torch.Tensor, shift) -> torch.Tensor: + ctx.quantum_circuit = circuit + ctx.shift = shift + + sim = ctx.quantum_circuit.simulate(x) + y = torch.tensor([sim]) + ctx.save_for_backward(x) + + return x + + @staticmethod + def backward(ctx, grad_output: torch.Tensor) -> Union[torch.Tensor, None]: + x = ctx.saved_tensors + x = x.detach().numpy() + + # Gradient evaluation with finite differences + shift_right = x + ctx.shift * np.ones(x.shape) + shift_left = x - ctx.shift * np.ones(x.shape) + + gradients = [] + for i in range(len(x)): + y_right = ctx.quantum_circuit.simulate(shift_right[i]) + y_left = ctx.quantum_circuit.simulate(shift_left[i]) + + gradient = torch.Tensor([(y_right - y_left) / (2 * ctx.shift)]) + gradients.append(gradient) + gradients = np.array(gradients).T + return grad_output.float() * torch.tensor([gradients]).float(), None + + +class QuantumNet(nn.Module): + def __init__(self, quantum_circuit: QuantumCircuit, shift) -> None: + super(QuantumNet, self).__init__() + self.quantum_circuit = quantum_circuit + self.shift = shift + + def forward(self, x): + return QuantumFunctions.apply(x, self.quantum_circuit, self.shift) + + +class HybridClassifier(nn.Module): + def __init__(self, quantum_net: ClassicalNet, classical_net: QuantumNet) -> None: + super(HybridClassifier, self).__init__() + self.classical_net = classical_net + self.quantum_net = quantum_net + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.classical_net(x) + x = self.quantum_net(x) + # Unsure about the return? + return x + + +def test_classifier(test_images: np.ndarray, test_labels: np.ndarray, classifier: qiskit.QuantumCircuit) -> Union[list, float]: + nb_test = len(test_images) + predictions = [] + for i in range(nb_test): + image = test_images[i] + _, prediction = run_part2(classifier, image) + predictions.append(prediction) + return predictions, mean_squared_error(test_labels, predictions) + + +def run_part2(pickle_path: str, image: np.ndarray) -> Union[qiskit.QuantumCircuit, int]: + # Load the quantum classifier circuit + with open(pickle_path, 'rb') as f: + classifier=pickle.load(f) + + # Build circuit + circuit = encode(image) + circuit.append(classifier) ## + + # Simulate circuit + histogram = simulator(circuit) + + # Convert histogram to category + label = histogram_to_category(histogram) + return circuit, label + + +if __name__ == "__main__": + images = np.load('data/images.npy') + labels = np.load('data/labels.npy') + train_images, train_labels, test_images, test_labels = split_train_test_data(images, labels) + + classifier = load_qasm('part2.qasm') # To be integrated to a classical NN + print(classifier) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d2aa05c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +matplotlib==3.6.3 +numpy==1.23.5 +Pillow==9.4.0 +qiskit==0.41.0 +qiskit_terra==0.22.4 +scikit_learn==1.2.1 +scipy==1.10.0 +torch==1.13.1 diff --git a/test.py b/test.py new file mode 100644 index 0000000..054cd57 --- /dev/null +++ b/test.py @@ -0,0 +1,311 @@ +"""The Somervillains - Code submission for the 2023 MIT iQuHack - IonQ Challenge + +Florent Pollet, Pierre Sibut-Bourde, Louis-Justin Tallot +28-29 January 2023 +""" + +team_name = "The Somervillains" + +import qiskit +from qiskit import quantum_info +from qiskit.execute_function import execute +from qiskit import BasicAer +import numpy as np +import pickle +import json +import os +import sys +from collections import Counter +from sklearn.metrics import mean_squared_error +from typing import Dict, List +import matplotlib.pyplot as plt + +if len(sys.argv) > 1: + data_path = sys.argv[1] +else: + data_path = '.' + +#define utility functions + +def simulate(circuit: qiskit.QuantumCircuit) -> dict: + """Simulate the circuit, give the state vector as the result.""" + backend = BasicAer.get_backend('statevector_simulator') + job = execute(circuit, backend) + result = job.result() + state_vector = result.get_statevector() + + histogram = dict() + for i in range(len(state_vector)): + population = abs(state_vector[i]) ** 2 + if population > 1e-9: + histogram[i] = population + + return histogram + + +def histogram_to_category(histogram): + """This function takes a histogram representation of circuit execution results, and processes into labels as described in + the problem description.""" + assert abs(sum(histogram.values())-1)<1e-8 + positive=0 + for key in histogram.keys(): + digits = bin(int(key))[2:].zfill(20) + if digits[-1]=='0': + positive+=histogram[key] + + return positive + +def count_gates(circuit: qiskit.QuantumCircuit) -> Dict[int, int]: + """Returns the number of gate operations with each number of qubits.""" + counter = Counter([len(gate[1]) for gate in circuit.data]) + #feel free to comment out the following two lines. But make sure you don't have k-qubit gates in your circuit + #for k>2 + for i in range(3,20): # only 1- and 2-qubit gates + assert counter[i]==0 + + return counter + + +def image_mse(image1,image2): + # Using sklearns mean squared error: + # https://scikit-learn.org/stable/modules/generated/sklearn.metrics.mean_squared_error.html + return mean_squared_error(255*image1,255*image2) + +def test(): + #load the actual hackthon data (fashion-mnist) + images=np.load(data_path+'/images.npy') + labels=np.load(data_path+'/labels.npy') + + #test part 1 + + n=len(images) + mse=0 + gatecount=0 + + for image in images: + #encode image into circuit + circuit,image_re=run_part1(image) + image_re = np.asarray(image_re) + + #count the number of 2qubit gates used + gatecount+=count_gates(circuit)[2] + + #calculate mse + mse+=image_mse(image,image_re) + + #fidelity of reconstruction + f=1-mse/n + gatecount=gatecount/n + + #score for part1 + score_part1=f*(0.999**gatecount) + + #test part 2 + + score=0 + gatecount=0 + n=len(images) + + for i in range(n): + #run part 2 + circuit,label=run_part2(images[i]) + + #count the gate used in the circuit for score calculation + gatecount+=count_gates(circuit)[2] + + #check label + if label==labels[i]: + score+=1 + #score + score=score/n + gatecount=gatecount/n + + score_part2=score*(0.999**gatecount) + + print(score_part1, ",", score_part2, ",", data_path, sep="") + + +############################ +# YOUR CODE HERE # +############################ +import math +from scipy.ndimage import zoom + +# Image properties +SIZE = 7 # Image width +NB_PX_IMG = SIZE ** 2 + +# quantum parameters +N = math.ceil(math.log2(SIZE)) +NB_QUBITS = 2 * N + 1 +NB_PX = 2 ** (2 * N) + + + +def pixel_value_to_theta(pixel: float) -> float: + return pixel / 255 * (np.pi / 2) + +def theta_to_pixel_value(theta: float) -> int: + return int(theta / (np.pi / 2) * 255) + +def get_proba(counts: dict) -> dict: + sums = sum(map(lambda x: x[1], counts.items())) + return {key: value / sums for key, value in counts.items()} + + +def recursive_ry(circuit, theta, mask): + if mask.sum() == 2: + idxs = np.where(mask == 1)[0] + circuit.cry(theta/2, idxs[0], NB_QUBITS - 1) + circuit.cx(idxs[0], idxs[1]) + circuit.cry(-theta/2, idxs[1], NB_QUBITS - 1) + circuit.cx(idxs[0], idxs[1]) + circuit.cry(theta/2, idxs[1], NB_QUBITS - 1) + else: + idx1, idx2 = np.where(mask == 1)[0][:2] + + maskn = mask.copy() + maskn[idx2] = 0 + recursive_ry(circuit, theta/2, maskn) + # c3ry = RYGate(theta).control(NB_QUBITS - 1) + # circuit.append(c3ry, ry_qbits) + circuit.cx(idx1, idx2) + + maskn = mask.copy() + maskn[idx1] = 0 + recursive_ry(circuit, -theta/2, maskn) + circuit.cx(idx1, idx2) + + maskn = mask.copy() + maskn[idx1] = 0 + recursive_ry(circuit, theta/2, maskn) + + + + +def encode(image): + circuit = qiskit.QuantumCircuit(NB_QUBITS) + image = image[::4, ::4] + # Get the theta values for each pixel + image = image.flatten() + thetas = [pixel_value_to_theta(pixel) for pixel in image] + thetas += [0] * (NB_PX - NB_PX_IMG) + + # Apply Hadamard gates for all qubits except the last one + for i in range(NB_QUBITS - 1): + circuit.h(i) + + switches = [bin(0)[2:].zfill(NB_QUBITS - 1)] + [ + bin(i ^ (i - 1))[2:].zfill(NB_QUBITS - 1) for i in range(1, NB_PX) + ] + + + # Apply the rotation gates + prev_switch = switches[0] + for i in range(NB_PX): + theta = thetas[i] # pixel_value_to_theta(intensity_count_expression[i][0]) + + # do not do zero rotation + if theta != 0: + switch = np.binary_repr(i, NB_QUBITS - 1) + + # Apply x gate to the i-th qubit if the i-th bit of the switch is 1 + for j in range(NB_QUBITS - 1): + if switch[j] != prev_switch[j]: + circuit.x(j) + # if switch[j] == "1": + # circuit.x(j - 1) + prev_switch = switch + + recursive_ry(circuit, 2*theta, np.array([1]*(NB_QUBITS - 1))) + + #circuit.barrier() + + # check all qbits are at 1 for the measurements + for j in range(NB_QUBITS - 1): + if prev_switch[j] != "1": + circuit.x(j) + + circuit.measure_all() + + from qiskit.transpiler.passes import RemoveBarriers + circuit = RemoveBarriers()(circuit) + + return circuit + +def decode(counts: dict) -> np.ndarray: + histogram = get_proba(counts) + img = np.zeros(NB_PX) # we have a square image + + for i in range(NB_PX): + bin_str: str = np.binary_repr(i, width=NB_QUBITS - 1) + + cos_str = "0" + bin_str[::-1] + sin_str = "1" + bin_str[::-1] + + theta = 0 + if cos_str in histogram: + prob_cos = histogram[cos_str] + theta = math.acos(np.clip(2**N * math.sqrt(prob_cos), 0, 1)) + else: + prob_cos = 0 + + # not needed? + if sin_str in histogram: + prob_sin = histogram[sin_str] + theta = math.asin(np.clip(2**N * math.sqrt(prob_sin), 0, 1)) + else: + prob_sin = 0 + + img[i] = theta_to_pixel_value(theta) + + img = img[:NB_PX_IMG] + img = img.reshape(SIZE, SIZE) + return zoom(img, 4, order=0) + +def run_part1(image): + #encode image into a circuit + circuit=encode(image) + + #simulate circuit + histogram=simulate(circuit) + + #reconstruct the image + image_re=decode(histogram) + + return circuit,image_re + +def run_part2(image): + # load the quantum classifier circuit + classifier=qiskit.QuantumCircuit.from_qasm_file('part2.qasm') + + #encode image into circuit + circuit=encode(image) + + #append with classifier circuit + nq1 = circuit.width() + nq2 = classifier.width() + nq = max(nq1, nq2) + qc = qiskit.QuantumCircuit(nq) + qc.append(circuit.to_instruction(), list(range(nq1))) + qc.append(classifier.to_instruction(), list(range(nq2))) + + #simulate circuit + histogram=simulate(qc) + + #convert histogram to category + label=histogram_to_category(histogram) + + #thresholding the label, any way you want + if label>0.5: + label=1 + else: + label=0 + + return circuit,label + +############################ +# END YOUR CODE # +############################ + +test() diff --git a/test_encoder_part1.py b/test_encoder_part1.py new file mode 100644 index 0000000..cfb3463 --- /dev/null +++ b/test_encoder_part1.py @@ -0,0 +1,66 @@ +import qiskit as qk +from qiskit import QuantumCircuit, Aer, IBMQ +from qiskit import transpile, assemble +from qiskit.tools.jupyter import * +from qiskit.visualization import plot_histogram +from math import pi +import matplotlib.pyplot as plt + +theta = [0, pi / 8, pi / 4, 3 * pi / 8] +qc = QuantumCircuit(3) + +qc.h(0) +qc.h(1) + +qc.barrier() +# Pixel 1 + +qc.cry(theta[0], 0, 2) +qc.cx(0, 1) +qc.cry(-theta[0], 1, 2) +qc.cx(0, 1) +qc.cry(theta[0], 1, 2) + +qc.barrier() +# Pixel 2 + +qc.x(1) +qc.cry(theta[1], 0, 2) +qc.cx(0, 1) +qc.cry(-theta[1], 1, 2) +qc.cx(0, 1) +qc.cry(theta[1], 1, 2) + +qc.barrier() + +qc.x(1) +qc.x(0) +qc.cry(theta[2], 0, 2) +qc.cx(0, 1) +qc.cry(-theta[2], 1, 2) +qc.cx(0, 1) +qc.cry(theta[2], 1, 2) + + +qc.barrier() + +qc.x(1) + +qc.cry(theta[3], 0, 2) +qc.cx(0, 1) +qc.cry(-theta[3], 1, 2) +qc.cx(0, 1) +qc.cry(theta[3], 1, 2) + +qc.measure_all() + +print(qc.draw()) + +aer_sim = Aer.get_backend('aer_simulator') +t_qc = transpile(qc, aer_sim) +qobj = assemble(t_qc, shots=4096) +result = aer_sim.run(qobj).result() +counts = result.get_counts(qc) +print(counts) +plot_histogram(counts) +plt.show() \ No newline at end of file