From 0b267cf3706ea88739776b632c9c34948acea484 Mon Sep 17 00:00:00 2001 From: Chanandellar Bong <75779966+AbdullahKazi500@users.noreply.github.com> Date: Sat, 1 Jun 2024 15:08:23 +0530 Subject: [PATCH 1/4] Add files via upload --- torchQuantumpulse.ipynb | 456 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 456 insertions(+) create mode 100644 torchQuantumpulse.ipynb diff --git a/torchQuantumpulse.ipynb b/torchQuantumpulse.ipynb new file mode 100644 index 00000000..81414a35 --- /dev/null +++ b/torchQuantumpulse.ipynb @@ -0,0 +1,456 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pNkofX47ENkt", + "outputId": "204c120e-4d1b-4f6e-e84a-43551bf2bd75" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Installing torchquantum...\n", + "Cloning into 'torchquantum'...\n", + "remote: Enumerating objects: 15128, done.\u001b[K\n", + "remote: Counting objects: 100% (1837/1837), done.\u001b[K\n", + "remote: Compressing objects: 100% (466/466), done.\u001b[K\n", + "remote: Total 15128 (delta 1519), reused 1483 (delta 1369), pack-reused 13291\u001b[K\n", + "Receiving objects: 100% (15128/15128), 98.00 MiB | 22.87 MiB/s, done.\n", + "Resolving deltas: 100% (8593/8593), done.\n", + "/content/torchquantum\n" + ] + } + ], + "source": [ + "print('Installing torchquantum...')\n", + "!git clone https://github.com/mit-han-lab/torchquantum.git\n", + "%cd /content/torchquantum\n", + "!pip install --editable . 1>/dev/null" + ] + }, + { + "cell_type": "code", + "source": [ + "import torch\n", + "import torch.optim as optim\n", + "import torchquantum as tq\n", + "import torchquantum.functional as tqf\n", + "import numpy as np\n", + "\n", + "class QuantumPulseDemo(tq.QuantumModule):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.n_wires = 2\n", + "\n", + " # Quantum encoder\n", + " self.encoder = tq.GeneralEncoder([\n", + " {'input_idx': [0], 'func': 'rx', 'wires': [0]},\n", + " {'input_idx': [1], 'func': 'rx', 'wires': [1]}\n", + " ])\n", + "\n", + " # Define parameterized quantum pulse\n", + " self.pulse = tq.pulse.QuantumPulseDirect(n_steps=4, hamil=[[0, 1], [1, 0]])\n", + "\n", + " def forward(self, x):\n", + " qdev = tq.QuantumDevice(n_wires=self.n_wires, bsz=x.shape[0], device=x.device)\n", + " self.encoder(qdev, x)\n", + " self.apply_pulse(qdev)\n", + " return tq.measure(qdev)\n", + "\n", + " def apply_pulse(self, qdev):\n", + " pulse_params = self.pulse.pulse_shape.detach().cpu().numpy()\n", + " # Apply pulse to the quantum device (adjust based on actual pulse application logic)\n", + " for i, params in enumerate(pulse_params):\n", + " tqf.rx(qdev, wires=0, params=params)\n", + " tqf.rx(qdev, wires=1, params=params)\n", + "\n", + "def main():\n", + " # Set up input data and target unitary\n", + " theta = 0.6\n", + " target_unitary = torch.tensor(\n", + " [\n", + " [np.cos(theta / 2), -1j * np.sin(theta / 2)],\n", + " [-1j * np.sin(theta / 2), np.cos(theta / 2)],\n", + " ],\n", + " dtype=torch.complex64,\n", + " )\n", + "\n", + " # Initialize the model and optimizer\n", + " model = QuantumPulseDemo()\n", + " optimizer = optim.Adam(params=model.pulse.parameters(), lr=5e-3)\n", + "\n", + " # Training loop\n", + " epochs = 1000\n", + " for epoch in range(epochs):\n", + " # Define input tensor (batch size 1, 2 features for 2 qubits)\n", + " x = torch.tensor([[np.pi, np.pi]], dtype=torch.float32)\n", + "\n", + " # Forward pass\n", + " qdev = model(x)\n", + "\n", + " # Compute loss\n", + " loss = (\n", + " 1\n", + " - (\n", + " torch.trace(model.pulse.get_unitary() @ target_unitary)\n", + " / target_unitary.shape[0]\n", + " ).abs()\n", + " ** 2\n", + " )\n", + "\n", + " # Backward pass and optimization\n", + " optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " # Print progress\n", + " if epoch % 100 == 0:\n", + " print(f'Epoch {epoch}, Loss: {loss.item()}')\n", + " print('Current Pulse Shape:', model.pulse.pulse_shape)\n", + " print('Current Unitary:', model.pulse.get_unitary())\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "HMgs9-fGGHJy", + "outputId": "6974e1d3-f7c1-42a7-b9f9-4af91c03018d" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 0, Loss: 0.8393601179122925\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.9950, 0.9950, 0.9950, 0.9950], requires_grad=True)\n", + "Current Unitary: tensor([[-0.6686+0.0000j, 0.0000+0.7436j],\n", + " [ 0.0000+0.7436j, -0.6686+0.0000j]], grad_fn=)\n", + "Epoch 100, Loss: 0.00020205974578857422\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7071, 0.7071, 0.7071, 0.7071], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9514+0.0000j, 0.0000-0.3080j],\n", + " [ 0.0000-0.3080j, -0.9514+0.0000j]], grad_fn=)\n", + "Epoch 200, Loss: 0.0\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 300, Loss: -2.384185791015625e-07\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 400, Loss: -2.384185791015625e-07\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 500, Loss: -2.384185791015625e-07\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 600, Loss: -2.384185791015625e-07\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 700, Loss: 0.0\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 800, Loss: 0.0\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 900, Loss: 0.0\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import torch\n", + "import torch.optim as optim\n", + "import torchquantum as tq\n", + "import torchquantum.functional as tqf\n", + "import numpy as np\n", + "\n", + "class QuantumPulseDemo(tq.QuantumModule):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.n_wires = 2\n", + "\n", + " # Quantum encoder\n", + " self.encoder = tq.GeneralEncoder([\n", + " {'input_idx': [0], 'func': 'rx', 'wires': [0]},\n", + " {'input_idx': [1], 'func': 'rx', 'wires': [1]}\n", + " ])\n", + "\n", + " # Define parameterized quantum pulse\n", + " self.pulse = tq.pulse.QuantumPulseDirect(n_steps=4, hamil=[[0, 1], [1, 0]])\n", + "\n", + " def forward(self, x):\n", + " qdev = tq.QuantumDevice(n_wires=self.n_wires, bsz=x.shape[0], device=x.device)\n", + " self.encoder(qdev, x)\n", + " self.apply_pulse(qdev)\n", + " return tq.measure(qdev)\n", + "\n", + " def apply_pulse(self, qdev):\n", + " pulse_params = self.pulse.pulse_shape.detach().cpu().numpy()\n", + " # Apply pulse to the quantum device (adjust based on actual pulse application logic)\n", + " for params in pulse_params:\n", + " tqf.rx(qdev, wires=0, params=params)\n", + " tqf.rx(qdev, wires=1, params=params)\n", + "\n", + "def main():\n", + " # Set up input data and target unitary\n", + " theta = 0.6\n", + " target_unitary = torch.tensor(\n", + " [\n", + " [np.cos(theta / 2), -1j * np.sin(theta / 2)],\n", + " [-1j * np.sin(theta / 2), np.cos(theta / 2)],\n", + " ],\n", + " dtype=torch.complex64,\n", + " )\n", + "\n", + " # Initialize the model and optimizer\n", + " model = QuantumPulseDemo()\n", + " optimizer = optim.Adam(params=model.pulse.parameters(), lr=5e-3)\n", + "\n", + " # Training loop\n", + " epochs = 1000\n", + " for epoch in range(epochs):\n", + " # Define input tensor (batch size 1, 2 features for 2 qubits)\n", + " x = torch.tensor([[np.pi, np.pi]], dtype=torch.float32)\n", + "\n", + " # Forward pass\n", + " qdev = model(x)\n", + "\n", + " # Compute loss\n", + " loss = (\n", + " 1\n", + " - (\n", + " torch.trace(model.pulse.get_unitary() @ target_unitary)\n", + " / target_unitary.shape[0]\n", + " ).abs()\n", + " ** 2\n", + " )\n", + "\n", + " # Backward pass and optimization\n", + " optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " # Print progress\n", + " if epoch % 100 == 0:\n", + " print(f'Epoch {epoch}, Loss: {loss.item()}')\n", + " print('Current Pulse Shape:', model.pulse.pulse_shape)\n", + " print('Current Unitary:\\n', model.pulse.get_unitary())\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "us_-lAAUGWoi", + "outputId": "8f462e33-bb5a-45a5-b074-7383cbd895ff" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 0, Loss: 0.8393601179122925\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.9950, 0.9950, 0.9950, 0.9950], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.6686+0.0000j, 0.0000+0.7436j],\n", + " [ 0.0000+0.7436j, -0.6686+0.0000j]], grad_fn=)\n", + "Epoch 100, Loss: 0.00020205974578857422\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7071, 0.7071, 0.7071, 0.7071], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9514+0.0000j, 0.0000-0.3080j],\n", + " [ 0.0000-0.3080j, -0.9514+0.0000j]], grad_fn=)\n", + "Epoch 200, Loss: 0.0\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 300, Loss: -2.384185791015625e-07\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 400, Loss: -2.384185791015625e-07\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 500, Loss: -2.384185791015625e-07\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 600, Loss: -2.384185791015625e-07\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 700, Loss: 0.0\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 800, Loss: 0.0\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", + "Epoch 900, Loss: 0.0\n", + "Current Pulse Shape: Parameter containing:\n", + "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", + "Current Unitary:\n", + " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", + " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "def apply_pulse(self, qdev):\n", + " pulse_params = self.pulse.pulse_shape.detach().cpu().numpy()\n", + " for params in pulse_params:\n", + " tq.phase_shift(qdev, wires=0, params=np.pi) # Apply pi phase shift before each pulse\n", + " tqf.rx(qdev, wires=0, params=params)\n" + ], + "metadata": { + "id": "ce9pmK8sHJEY" + }, + "execution_count": 10, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "\n", + "\n", + "class OM_EOM_Simulation:\n", + " def __init__(self, pulse_duration, modulation_bandwidth=None, eom_mode=False):\n", + " self.pulse_duration = pulse_duration\n", + " self.modulation_bandwidth = modulation_bandwidth\n", + " self.eom_mode = eom_mode\n", + "\n", + " def simulate_sequence(self):\n", + " # Initialize the sequence\n", + " sequence = []\n", + "\n", + " # Add pulses and delays to the sequence\n", + " if self.modulation_bandwidth:\n", + " # Apply modulation bandwidth effect\n", + " sequence.append(('Delay', 0))\n", + " sequence.append(('Pulse', 'NoisyChannel'))\n", + " for _ in range(3):\n", + " # Apply pulses with specified duration\n", + " sequence.append(('Delay', self.pulse_duration))\n", + " if self.eom_mode:\n", + " # Apply EOM mode operation\n", + " sequence.append(('Pulse', 'EOM'))\n", + " else:\n", + " # Apply regular pulse\n", + " sequence.append(('Pulse', 'Regular'))\n", + " # Apply a delay between pulses\n", + " sequence.append(('Delay', 0))\n", + "\n", + " return sequence\n", + "\n", + "# Define parameters for the simulation\n", + "pulse_duration = 100\n", + "modulation_bandwidth = 5\n", + "eom_mode = True\n", + "\n", + "# Create the simulation object\n", + "sim = OM_EOM_Simulation(pulse_duration, modulation_bandwidth, eom_mode)\n", + "\n", + "# Simulate the sequence\n", + "sequence = sim.simulate_sequence()\n", + "\n", + "# Print the sequence\n", + "for step in sequence:\n", + " print(step)\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wd-athV2IMx_", + "outputId": "b034d9bd-836a-4652-caf2-fd078b8fb761" + }, + "execution_count": 15, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "('Delay', 0)\n", + "('Pulse', 'NoisyChannel')\n", + "('Delay', 100)\n", + "('Pulse', 'EOM')\n", + "('Delay', 0)\n", + "('Delay', 100)\n", + "('Pulse', 'EOM')\n", + "('Delay', 0)\n", + "('Delay', 100)\n", + "('Pulse', 'EOM')\n", + "('Delay', 0)\n" + ] + } + ] + } + ] +} \ No newline at end of file From 968c21bad76eec00b74988dda331e12b368692f0 Mon Sep 17 00:00:00 2001 From: Chanandellar Bong <75779966+AbdullahKazi500@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:30:11 +0530 Subject: [PATCH 2/4] Create quantum_pulse_simulation.py --- .../pulse/quantum_pulse_simulation.py | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 torchquantum/pulse/quantum_pulse_simulation.py diff --git a/torchquantum/pulse/quantum_pulse_simulation.py b/torchquantum/pulse/quantum_pulse_simulation.py new file mode 100644 index 00000000..45ed19fa --- /dev/null +++ b/torchquantum/pulse/quantum_pulse_simulation.py @@ -0,0 +1,183 @@ +import torch +import torch.optim as optim +import torchquantum as tq +import torchquantum.functional as tqf +import numpy as np + +class QuantumPulseDemo(tq.QuantumModule): + """ + Quantum pulse demonstration module. + + This module defines a parameterized quantum pulse and applies it to a quantum device. + """ + + def __init__(self): + """ + Initializes the QuantumPulseDemo module. + """ + super().__init__() + self.n_wires = 2 + + # Quantum encoder + self.encoder = tq.GeneralEncoder([ + {'input_idx': [0], 'func': 'rx', 'wires': [0]}, + {'input_idx': [1], 'func': 'rx', 'wires': [1]} + ]) + + # Define parameterized quantum pulse + self.pulse = tq.pulse.QuantumPulseDirect(n_steps=4, hamil=[[0, 1], [1, 0]]) + + def forward(self, x): + """ + Forward pass through the QuantumPulseDemo module. + + Args: + x (torch.Tensor): Input tensor. + + Returns: + torch.Tensor: Measurement result from the quantum device. + """ + qdev = tq.QuantumDevice(n_wires=self.n_wires, bsz=x.shape[0], device=x.device) + self.encoder(qdev, x) + self.apply_pulse(qdev) + return tq.measure(qdev) + + def apply_pulse(self, qdev): + """ + Applies the parameterized quantum pulse to the quantum device. + + Args: + qdev (tq.QuantumDevice): Quantum device to apply the pulse to. + """ + pulse_params = self.pulse.pulse_shape.detach().cpu().numpy() + # Apply pulse to the quantum device (adjust based on actual pulse application logic) + for params in pulse_params: + tqf.rx(qdev, wires=0, params=params) + tqf.rx(qdev, wires=1, params=params) + +class OM_EOM_Simulation: + """ + Optical modulation with electro-optic modulator (EOM) simulation. + + This class simulates a sequence of optical pulses with or without EOM modulation. + """ + + def __init__(self, pulse_duration, modulation_bandwidth=None, eom_mode=False): + """ + Initializes the OM_EOM_Simulation. + + Args: + pulse_duration (float): Duration of each pulse. + modulation_bandwidth (float, optional): Bandwidth of modulation. Defaults to None. + eom_mode (bool, optional): Whether to simulate EOM mode. Defaults to False. + """ + self.pulse_duration = pulse_duration + self.modulation_bandwidth = modulation_bandwidth + self.eom_mode = eom_mode + + def simulate_sequence(self): + """ + Simulates a sequence of optical pulses with specified parameters. + + Returns: + list: Sequence of pulses and delays. + """ + # Initialize the sequence + sequence = [] + + # Add pulses and delays to the sequence + if self.modulation_bandwidth: + # Apply modulation bandwidth effect + sequence.append(('Delay', 0)) + sequence.append(('Pulse', 'NoisyChannel')) + for _ in range(3): + # Apply pulses with specified duration + sequence.append(('Delay', self.pulse_duration)) + if self.eom_mode: + # Apply EOM mode operation + sequence.append(('Pulse', 'EOM')) + else: + # Apply regular pulse + sequence.append(('Pulse', 'Regular')) + # Apply a delay between pulses + sequence.append(('Delay', 0)) + + return sequence + +class QuantumPulseDemoRunner: + """ + Runner for training the QuantumPulseDemo model and simulating the OM_EOM_Simulation. + """ + + def __init__(self, pulse_duration, modulation_bandwidth=None, eom_mode=False): + """ + Initializes the QuantumPulseDemoRunner. + + Args: + pulse_duration (float): Duration of each pulse. + modulation_bandwidth (float, optional): Bandwidth of modulation. Defaults to None. + eom_mode (bool, optional): Whether to simulate EOM mode. Defaults to False. + """ + self.model = QuantumPulseDemo() + self.optimizer = optim.Adam(params=self.model.pulse.parameters(), lr=5e-3) + self.target_unitary = self._initialize_target_unitary() + self.simulator = OM_EOM_Simulation(pulse_duration, modulation_bandwidth, eom_mode) + + def _initialize_target_unitary(self): + """ + Initializes the target unitary matrix. + + Returns: + torch.Tensor: Target unitary matrix. + """ + theta = 0.6 + return torch.tensor( + [ + [np.cos(theta / 2), -1j * np.sin(theta / 2)], + [-1j * np.sin(theta / 2), np.cos(theta / 2)], + ], + dtype=torch.complex64, + ) + + def train(self, epochs=1000): + """ + Trains the QuantumPulseDemo model. + + Args: + epochs (int, optional): Number of training epochs. Defaults to 1000. + """ + for epoch in range(epochs): + x = torch.tensor([[np.pi, np.pi]], dtype=torch.float32) + + qdev = self.model(x) + + loss = ( + 1 + - ( + torch.trace(self.model.pulse.get_unitary() @ self.target_unitary) + / self.target_unitary.shape[0] + ).abs() + ** 2 + ) + + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + + if epoch % 100 == 0: + print(f'Epoch {epoch}, Loss: {loss.item()}') + print('Current Pulse Shape:', self.model.pulse.pulse_shape) + print('Current Unitary:\n', self.model.pulse.get_unitary()) + + def run_simulation(self): + """ + Runs the OM_EOM_Simulation. + """ + sequence = self.simulator.simulate_sequence() + for step in sequence: + print(step) + +# Example usage +runner = QuantumPulseDemoRunner(pulse_duration=100, modulation_bandwidth=5, eom_mode=True) +runner.train() +runner.run_simulation() From 0f0de3f130e23cf8339a2931534a3f4f747f7ff2 Mon Sep 17 00:00:00 2001 From: Chanandellar Bong <75779966+AbdullahKazi500@users.noreply.github.com> Date: Thu, 13 Jun 2024 00:00:03 +0530 Subject: [PATCH 3/4] Delete torchQuantumpulse.ipynb --- torchQuantumpulse.ipynb | 456 ---------------------------------------- 1 file changed, 456 deletions(-) delete mode 100644 torchQuantumpulse.ipynb diff --git a/torchQuantumpulse.ipynb b/torchQuantumpulse.ipynb deleted file mode 100644 index 81414a35..00000000 --- a/torchQuantumpulse.ipynb +++ /dev/null @@ -1,456 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "pNkofX47ENkt", - "outputId": "204c120e-4d1b-4f6e-e84a-43551bf2bd75" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Installing torchquantum...\n", - "Cloning into 'torchquantum'...\n", - "remote: Enumerating objects: 15128, done.\u001b[K\n", - "remote: Counting objects: 100% (1837/1837), done.\u001b[K\n", - "remote: Compressing objects: 100% (466/466), done.\u001b[K\n", - "remote: Total 15128 (delta 1519), reused 1483 (delta 1369), pack-reused 13291\u001b[K\n", - "Receiving objects: 100% (15128/15128), 98.00 MiB | 22.87 MiB/s, done.\n", - "Resolving deltas: 100% (8593/8593), done.\n", - "/content/torchquantum\n" - ] - } - ], - "source": [ - "print('Installing torchquantum...')\n", - "!git clone https://github.com/mit-han-lab/torchquantum.git\n", - "%cd /content/torchquantum\n", - "!pip install --editable . 1>/dev/null" - ] - }, - { - "cell_type": "code", - "source": [ - "import torch\n", - "import torch.optim as optim\n", - "import torchquantum as tq\n", - "import torchquantum.functional as tqf\n", - "import numpy as np\n", - "\n", - "class QuantumPulseDemo(tq.QuantumModule):\n", - " def __init__(self):\n", - " super().__init__()\n", - " self.n_wires = 2\n", - "\n", - " # Quantum encoder\n", - " self.encoder = tq.GeneralEncoder([\n", - " {'input_idx': [0], 'func': 'rx', 'wires': [0]},\n", - " {'input_idx': [1], 'func': 'rx', 'wires': [1]}\n", - " ])\n", - "\n", - " # Define parameterized quantum pulse\n", - " self.pulse = tq.pulse.QuantumPulseDirect(n_steps=4, hamil=[[0, 1], [1, 0]])\n", - "\n", - " def forward(self, x):\n", - " qdev = tq.QuantumDevice(n_wires=self.n_wires, bsz=x.shape[0], device=x.device)\n", - " self.encoder(qdev, x)\n", - " self.apply_pulse(qdev)\n", - " return tq.measure(qdev)\n", - "\n", - " def apply_pulse(self, qdev):\n", - " pulse_params = self.pulse.pulse_shape.detach().cpu().numpy()\n", - " # Apply pulse to the quantum device (adjust based on actual pulse application logic)\n", - " for i, params in enumerate(pulse_params):\n", - " tqf.rx(qdev, wires=0, params=params)\n", - " tqf.rx(qdev, wires=1, params=params)\n", - "\n", - "def main():\n", - " # Set up input data and target unitary\n", - " theta = 0.6\n", - " target_unitary = torch.tensor(\n", - " [\n", - " [np.cos(theta / 2), -1j * np.sin(theta / 2)],\n", - " [-1j * np.sin(theta / 2), np.cos(theta / 2)],\n", - " ],\n", - " dtype=torch.complex64,\n", - " )\n", - "\n", - " # Initialize the model and optimizer\n", - " model = QuantumPulseDemo()\n", - " optimizer = optim.Adam(params=model.pulse.parameters(), lr=5e-3)\n", - "\n", - " # Training loop\n", - " epochs = 1000\n", - " for epoch in range(epochs):\n", - " # Define input tensor (batch size 1, 2 features for 2 qubits)\n", - " x = torch.tensor([[np.pi, np.pi]], dtype=torch.float32)\n", - "\n", - " # Forward pass\n", - " qdev = model(x)\n", - "\n", - " # Compute loss\n", - " loss = (\n", - " 1\n", - " - (\n", - " torch.trace(model.pulse.get_unitary() @ target_unitary)\n", - " / target_unitary.shape[0]\n", - " ).abs()\n", - " ** 2\n", - " )\n", - "\n", - " # Backward pass and optimization\n", - " optimizer.zero_grad()\n", - " loss.backward()\n", - " optimizer.step()\n", - "\n", - " # Print progress\n", - " if epoch % 100 == 0:\n", - " print(f'Epoch {epoch}, Loss: {loss.item()}')\n", - " print('Current Pulse Shape:', model.pulse.pulse_shape)\n", - " print('Current Unitary:', model.pulse.get_unitary())\n", - "\n", - "if __name__ == \"__main__\":\n", - " main()\n" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "HMgs9-fGGHJy", - "outputId": "6974e1d3-f7c1-42a7-b9f9-4af91c03018d" - }, - "execution_count": 6, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Epoch 0, Loss: 0.8393601179122925\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.9950, 0.9950, 0.9950, 0.9950], requires_grad=True)\n", - "Current Unitary: tensor([[-0.6686+0.0000j, 0.0000+0.7436j],\n", - " [ 0.0000+0.7436j, -0.6686+0.0000j]], grad_fn=)\n", - "Epoch 100, Loss: 0.00020205974578857422\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7071, 0.7071, 0.7071, 0.7071], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9514+0.0000j, 0.0000-0.3080j],\n", - " [ 0.0000-0.3080j, -0.9514+0.0000j]], grad_fn=)\n", - "Epoch 200, Loss: 0.0\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 300, Loss: -2.384185791015625e-07\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 400, Loss: -2.384185791015625e-07\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 500, Loss: -2.384185791015625e-07\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 600, Loss: -2.384185791015625e-07\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 700, Loss: 0.0\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 800, Loss: 0.0\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 900, Loss: 0.0\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary: tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n" - ] - } - ] - }, - { - "cell_type": "code", - "source": [ - "import torch\n", - "import torch.optim as optim\n", - "import torchquantum as tq\n", - "import torchquantum.functional as tqf\n", - "import numpy as np\n", - "\n", - "class QuantumPulseDemo(tq.QuantumModule):\n", - " def __init__(self):\n", - " super().__init__()\n", - " self.n_wires = 2\n", - "\n", - " # Quantum encoder\n", - " self.encoder = tq.GeneralEncoder([\n", - " {'input_idx': [0], 'func': 'rx', 'wires': [0]},\n", - " {'input_idx': [1], 'func': 'rx', 'wires': [1]}\n", - " ])\n", - "\n", - " # Define parameterized quantum pulse\n", - " self.pulse = tq.pulse.QuantumPulseDirect(n_steps=4, hamil=[[0, 1], [1, 0]])\n", - "\n", - " def forward(self, x):\n", - " qdev = tq.QuantumDevice(n_wires=self.n_wires, bsz=x.shape[0], device=x.device)\n", - " self.encoder(qdev, x)\n", - " self.apply_pulse(qdev)\n", - " return tq.measure(qdev)\n", - "\n", - " def apply_pulse(self, qdev):\n", - " pulse_params = self.pulse.pulse_shape.detach().cpu().numpy()\n", - " # Apply pulse to the quantum device (adjust based on actual pulse application logic)\n", - " for params in pulse_params:\n", - " tqf.rx(qdev, wires=0, params=params)\n", - " tqf.rx(qdev, wires=1, params=params)\n", - "\n", - "def main():\n", - " # Set up input data and target unitary\n", - " theta = 0.6\n", - " target_unitary = torch.tensor(\n", - " [\n", - " [np.cos(theta / 2), -1j * np.sin(theta / 2)],\n", - " [-1j * np.sin(theta / 2), np.cos(theta / 2)],\n", - " ],\n", - " dtype=torch.complex64,\n", - " )\n", - "\n", - " # Initialize the model and optimizer\n", - " model = QuantumPulseDemo()\n", - " optimizer = optim.Adam(params=model.pulse.parameters(), lr=5e-3)\n", - "\n", - " # Training loop\n", - " epochs = 1000\n", - " for epoch in range(epochs):\n", - " # Define input tensor (batch size 1, 2 features for 2 qubits)\n", - " x = torch.tensor([[np.pi, np.pi]], dtype=torch.float32)\n", - "\n", - " # Forward pass\n", - " qdev = model(x)\n", - "\n", - " # Compute loss\n", - " loss = (\n", - " 1\n", - " - (\n", - " torch.trace(model.pulse.get_unitary() @ target_unitary)\n", - " / target_unitary.shape[0]\n", - " ).abs()\n", - " ** 2\n", - " )\n", - "\n", - " # Backward pass and optimization\n", - " optimizer.zero_grad()\n", - " loss.backward()\n", - " optimizer.step()\n", - "\n", - " # Print progress\n", - " if epoch % 100 == 0:\n", - " print(f'Epoch {epoch}, Loss: {loss.item()}')\n", - " print('Current Pulse Shape:', model.pulse.pulse_shape)\n", - " print('Current Unitary:\\n', model.pulse.get_unitary())\n", - "\n", - "if __name__ == \"__main__\":\n", - " main()\n" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "us_-lAAUGWoi", - "outputId": "8f462e33-bb5a-45a5-b074-7383cbd895ff" - }, - "execution_count": 7, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Epoch 0, Loss: 0.8393601179122925\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.9950, 0.9950, 0.9950, 0.9950], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.6686+0.0000j, 0.0000+0.7436j],\n", - " [ 0.0000+0.7436j, -0.6686+0.0000j]], grad_fn=)\n", - "Epoch 100, Loss: 0.00020205974578857422\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7071, 0.7071, 0.7071, 0.7071], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9514+0.0000j, 0.0000-0.3080j],\n", - " [ 0.0000-0.3080j, -0.9514+0.0000j]], grad_fn=)\n", - "Epoch 200, Loss: 0.0\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 300, Loss: -2.384185791015625e-07\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 400, Loss: -2.384185791015625e-07\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 500, Loss: -2.384185791015625e-07\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 600, Loss: -2.384185791015625e-07\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 700, Loss: 0.0\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 800, Loss: 0.0\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n", - "Epoch 900, Loss: 0.0\n", - "Current Pulse Shape: Parameter containing:\n", - "tensor([0.7104, 0.7104, 0.7104, 0.7104], requires_grad=True)\n", - "Current Unitary:\n", - " tensor([[-0.9553+0.0000j, 0.0000-0.2955j],\n", - " [ 0.0000-0.2955j, -0.9553+0.0000j]], grad_fn=)\n" - ] - } - ] - }, - { - "cell_type": "code", - "source": [ - "def apply_pulse(self, qdev):\n", - " pulse_params = self.pulse.pulse_shape.detach().cpu().numpy()\n", - " for params in pulse_params:\n", - " tq.phase_shift(qdev, wires=0, params=np.pi) # Apply pi phase shift before each pulse\n", - " tqf.rx(qdev, wires=0, params=params)\n" - ], - "metadata": { - "id": "ce9pmK8sHJEY" - }, - "execution_count": 10, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "\n", - "\n", - "class OM_EOM_Simulation:\n", - " def __init__(self, pulse_duration, modulation_bandwidth=None, eom_mode=False):\n", - " self.pulse_duration = pulse_duration\n", - " self.modulation_bandwidth = modulation_bandwidth\n", - " self.eom_mode = eom_mode\n", - "\n", - " def simulate_sequence(self):\n", - " # Initialize the sequence\n", - " sequence = []\n", - "\n", - " # Add pulses and delays to the sequence\n", - " if self.modulation_bandwidth:\n", - " # Apply modulation bandwidth effect\n", - " sequence.append(('Delay', 0))\n", - " sequence.append(('Pulse', 'NoisyChannel'))\n", - " for _ in range(3):\n", - " # Apply pulses with specified duration\n", - " sequence.append(('Delay', self.pulse_duration))\n", - " if self.eom_mode:\n", - " # Apply EOM mode operation\n", - " sequence.append(('Pulse', 'EOM'))\n", - " else:\n", - " # Apply regular pulse\n", - " sequence.append(('Pulse', 'Regular'))\n", - " # Apply a delay between pulses\n", - " sequence.append(('Delay', 0))\n", - "\n", - " return sequence\n", - "\n", - "# Define parameters for the simulation\n", - "pulse_duration = 100\n", - "modulation_bandwidth = 5\n", - "eom_mode = True\n", - "\n", - "# Create the simulation object\n", - "sim = OM_EOM_Simulation(pulse_duration, modulation_bandwidth, eom_mode)\n", - "\n", - "# Simulate the sequence\n", - "sequence = sim.simulate_sequence()\n", - "\n", - "# Print the sequence\n", - "for step in sequence:\n", - " print(step)\n" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "wd-athV2IMx_", - "outputId": "b034d9bd-836a-4652-caf2-fd078b8fb761" - }, - "execution_count": 15, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "('Delay', 0)\n", - "('Pulse', 'NoisyChannel')\n", - "('Delay', 100)\n", - "('Pulse', 'EOM')\n", - "('Delay', 0)\n", - "('Delay', 100)\n", - "('Pulse', 'EOM')\n", - "('Delay', 0)\n", - "('Delay', 100)\n", - "('Pulse', 'EOM')\n", - "('Delay', 0)\n" - ] - } - ] - } - ] -} \ No newline at end of file From 82cf1847d2d74bd798fa4329f1585bab70ecdfce Mon Sep 17 00:00:00 2001 From: Chanandellar Bong <75779966+AbdullahKazi500@users.noreply.github.com> Date: Thu, 13 Jun 2024 02:31:44 +0530 Subject: [PATCH 4/4] Update quantum_pulse_simulation.py --- torchquantum/pulse/quantum_pulse_simulation.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/torchquantum/pulse/quantum_pulse_simulation.py b/torchquantum/pulse/quantum_pulse_simulation.py index 45ed19fa..703f097d 100644 --- a/torchquantum/pulse/quantum_pulse_simulation.py +++ b/torchquantum/pulse/quantum_pulse_simulation.py @@ -14,6 +14,11 @@ class QuantumPulseDemo(tq.QuantumModule): def __init__(self): """ Initializes the QuantumPulseDemo module. + + Args: + n_wires (int): Number of quantum wires (qubits). + n_steps (int): Number of steps for the quantum pulse. + hamil (list): Hamiltonian for the quantum pulse. """ super().__init__() self.n_wires = 2