diff --git a/Dcsp example.ipynb b/Dcsp example.ipynb new file mode 100644 index 0000000..d7b2efa --- /dev/null +++ b/Dcsp example.ipynb @@ -0,0 +1,309 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 19, + "id": "inner-welsh", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + "Ref.: A divide-and-conquer algorithm for quantum state preparation\n", + "https://arxiv.org/abs/2008.01511\n", + "\"\"\"\n", + "import pennylane as qml\n", + "from pennylane import numpy as np\n", + "\n", + "class bin_heap:\n", + " size = None\n", + " values = None\n", + "\n", + " def __init__(self, values):\n", + " self.size = len(values)\n", + " self.values = values\n", + "\n", + " def parent(self, key):\n", + " return int((key-0.5)/2)\n", + "\n", + " def left(self, key):\n", + " return int(2 * key + 1)\n", + "\n", + " def right(self, key):\n", + " return int(2 * key + 2)\n", + "\n", + " def root(self):\n", + " return 0\n", + "\n", + " def __getitem__(self, key):\n", + " return self.values[key]\n", + "\n", + "\n", + "class Encoding:\n", + " quantum_data = None\n", + " classical_data = None\n", + " num_qubits = None\n", + " heap = None\n", + " output_qubits = []\n", + "\n", + " def __init__(self, q, input_vector, encode_type='amplitude_encoding'):\n", + " self.output_qubits = []\n", + " if encode_type == 'dc_amplitude_encoding':\n", + " self.dc_amplitude_encoding(q, input_vector)\n", + " elif encode_type == 'dc_amplitude_encoding_orthonormal_ancillary':\n", + " self.dc_amplitude_encoding_orthonormal_ancillary(q, input_vector)\n", + "\n", + " @staticmethod\n", + " def _recursive_compute_beta(input_vector, betas):\n", + " if len(input_vector) > 1:\n", + " new_x = []\n", + " beta = []\n", + " for j in range(0, len(input_vector), 2):\n", + " norm = np.sqrt(input_vector[j] ** 2 + input_vector[j + 1] ** 2)\n", + " new_x.append(norm)\n", + " if norm == 0:\n", + " beta.append(0)\n", + " else:\n", + " if input_vector[j] < 0:\n", + " beta.append(2 * np.pi - 2 * np.arcsin(input_vector[j + 1] / norm))\n", + " else:\n", + " beta.append(2 * np.arcsin(input_vector[j + 1] / norm))\n", + " Encoding._recursive_compute_beta(new_x, betas)\n", + " betas.append(beta)\n", + "\n", + " @staticmethod\n", + " def _recursive_compute_beta_z(input_vector, betas):\n", + " if len(input_vector) > 1:\n", + " new_x = []\n", + " beta = []\n", + " for j in range(0, len(input_vector), 2):\n", + " new_x.append((input_vector[j+1]+input_vector[j])/2)\n", + " beta.append(input_vector[j+1]-input_vector[j])\n", + " \n", + " Encoding._recursive_compute_beta_z(new_x, betas)\n", + " betas.append(beta)\n", + "\n", + " def dc_amplitude_encoding_orthonormal_ancillary(self, q, input_vector):\n", + " self.dc_amplitude_encoding(q, input_vector)\n", + " \n", + " q_ortho = q[self.num_qubits:]\n", + " n = len(self.output_qubits)\n", + " self.num_qubits += n\n", + " for i in range(n):\n", + " qml.CNOT(wires=[self.output_qubits[i], q_ortho[i]])\n", + "\n", + " def dc_amplitude_encoding(self, q, input_vector):\n", + " self.num_qubits = int(len(input_vector))-1\n", + " self.quantum_data = q[:self.num_qubits]\n", + " betas_y = []\n", + " betas_z = []\n", + "\n", + " newx = np.copy(input_vector)\n", + " \n", + " Encoding._recursive_compute_beta(np.abs(newx), betas_y)\n", + " Encoding._recursive_compute_beta_z(np.angle(newx), betas_z)\n", + " \n", + " self._dc_generate_circuit(betas_y, betas_z, self.quantum_data)\n", + "\n", + " def _dc_generate_circuit(self, betas_y, betas_z, quantum_input):\n", + " k = 0\n", + " for angles in betas_y:\n", + " for angle in angles:\n", + " qml.RY(angle, wires=quantum_input[k])\n", + " k += 1\n", + "\n", + " k = 0\n", + " for angles in betas_z:\n", + " for angle in angles:\n", + " qml.RZ(angle, wires=quantum_input[k])\n", + " k += 1\n", + " \n", + " self.heap = bin_heap(quantum_input)\n", + " my_heap = self.heap\n", + "\n", + " last = my_heap.size - 1\n", + " actual = my_heap.parent(last)\n", + " level = my_heap.parent(last)\n", + " while actual >= 0:\n", + " left_index = my_heap.left(actual)\n", + " right_index = my_heap.right(actual)\n", + " while right_index <= last:\n", + " qml.CSWAP(wires=[my_heap[actual], my_heap[left_index], my_heap[right_index]])\n", + " left_index = my_heap.left(left_index)\n", + " right_index = my_heap.left(right_index)\n", + " actual -= 1\n", + " if level != my_heap.parent(actual):\n", + " level -= 1\n", + " \n", + " # set output qubits\n", + " next_index = 0\n", + " while next_index < my_heap.size:\n", + " self.output_qubits.append(quantum_input[next_index])\n", + " next_index = my_heap.left(next_index)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "coordinated-michael", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + "Circuits used for testing.\n", + "\"\"\"\n", + "qml.enable_tape()\n", + "\n", + "dev_amp = qml.device(\"default.qubit\", wires=3)\n", + "dev_dc = qml.device(\"default.qubit\", wires=7)\n", + "\n", + "\"\"\"\n", + "Amplitude encoding, used for comparison.\n", + "\"\"\"\n", + "@qml.qnode(dev_amp)\n", + "def test_amp(state_vector=None):\n", + " q=range(3)\n", + " \n", + " qml.templates.AmplitudeEmbedding(state_vector, wires=q)\n", + " \n", + " return qml.probs(wires=q)\n", + "\"\"\"\n", + "Divide-and-conquer encoding.\n", + "\"\"\"\n", + "@qml.qnode(dev_dc)\n", + "def test_dcsp(state_vector=None):\n", + "\n", + " encode = Encoding(range(10), state_vector, 'dc_amplitude_encoding')\n", + " q = encode.output_qubits \n", + " \n", + " return qml.probs(wires=q)\n", + "\n", + "@qml.qnode(dev_dc)\n", + "def test_dcsp_state(state_vector=None):\n", + "\n", + " encode = Encoding(range(10), state_vector, 'dc_amplitude_encoding')\n", + " q = encode.output_qubits \n", + " \n", + " return qml.state()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "designed-illustration", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + "State to be loaded.\n", + "\"\"\"\n", + "state_vector_1 = [np.sqrt(0.03)*np.exp(1.0j), np.sqrt(0.07)*np.exp(1.1j), np.sqrt(0.15)*np.exp(1.22j), np.sqrt(0.05)*np.exp(1.3j), np.sqrt(0.1)*np.exp(1.4j), np.sqrt(0.3)*np.exp(1.55j), np.sqrt(0.2)*np.exp(1.6j), np.sqrt(0.1)*np.exp(1.7j) ]" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "fallen-opinion", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Amplitude encoding:\n", + "probabilities:\n", + "[0.03 0.07 0.15 0.05 0.1 0.3 0.2 0.1 ]\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "Amplitude enconding, to be used as a reference.\n", + "\"\"\"\n", + "print(\"Amplitude encoding:\")\n", + "print(\"probabilities:\")\n", + "print(test_amp(state_vector=state_vector_1))" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "variable-light", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dcsp encoding:\n", + "probabilities:\n", + "[0.03 0.07 0.15 0.05 0.1 0.3 0.2 0.1 ]\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "Dcsp state preparation.\n", + "\"\"\"\n", + "print(\"Dcsp encoding:\")\n", + "print(\"probabilities:\")\n", + "print(test_dcsp(state_vector=state_vector_1))" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "roman-excitement", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dcsp circuit diagram:\n", + " 0: ──RY(1.98)──RZ(0.407)────────────────╭C─────╭C─────╭┤ Probs \n", + " 1: ──RY(1.91)──RZ(0.21)──────────╭C─────├SWAP──│──────├┤ Probs \n", + " 2: ──RY(1.43)──RZ(0.175)──╭C─────│──────╰SWAP──│──────│┤ \n", + " 3: ──RY(1.98)──RZ(0.1)────│──────├SWAP─────────├SWAP──╰┤ Probs \n", + " 4: ──RY(1.05)──RZ(0.08)───│──────╰SWAP─────────│───────┤ \n", + " 5: ──RY(2.09)──RZ(0.15)───├SWAP────────────────╰SWAP───┤ \n", + " 6: ──RY(1.23)──RZ(0.1)────╰SWAP────────────────────────┤ \n", + "\n" + ] + } + ], + "source": [ + "print(\"Dcsp circuit diagram:\")\n", + "print(test_dcsp.draw())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "accepting-serve", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.7.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}