Skip to content

Commit

Permalink
Merge pull request #169 from sequence-toolbox/RnD
Browse files Browse the repository at this point in the history
Version 0.6.2
  • Loading branch information
Alex-Kolar authored Sep 22, 2023
2 parents 4b78ffd + 04bc17d commit da36d3d
Show file tree
Hide file tree
Showing 22 changed files with 1,204 additions and 89 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Removed
- Removed support for scipy version 1.11. This is currently causing some issues with qutip.

## [0.6.2]
### Added
- Moved around and added a few files in the `examples` folder
- These are primarily for the IEEE QCE 2023 conference

### Changed
- Modified the topology output of the GUI to be compatible with new topology upgrades
- Several bug fixes in the GUI
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
author = 'Xiaoliang Wu, Joaquin Chung, Alexander Kolar, Eugene Wang, Tian Zhong, Rajkumar Kettimuthu, Martin Suchara'

# The full version, including alpha/beta/rc tags
release = '0.6.1'
release = '0.6.2'


# -- General configuration ---------------------------------------------------
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
360 changes: 360 additions & 0 deletions example/QCE_demos_2023/GUI_and_code_demo.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,360 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Network with Applications\n",
"\n",
"In this file, we'll demonstrate the simulation of a more complicated network topology with applications. These applications will act on each node, requesting memories to be entangled and then recording metrics. The network topology, including hardware components, is shown below:\n",
"\n",
"<img src=\"./images/star_network.png\" width=\"800\"/>\n",
"\n",
"In this file, we construct the network described above and add a custom app to two nodes. Most of the code has been written, but some will need to be filled in. We'll be building the topology from an external json file constructed using the GUI.\n",
"\n",
"## Imports\n",
"We must first import the necessary tools from SeQUeNCe. For building our specific request, we will import:\n",
"\n",
"- `RequestApp` is an example application included with SeQUeNCe. We will investigate its behavior through a class that inherits from this.\n",
"- `Message` is a wrapper for classical messages to exchange between nodes.\n",
"\n",
"Finally, for creating the network itself, we will import:\n",
"\n",
"- `Topology` is a powerful class for creating and managing complex network topologies. We'll be using the `RouterNetTopo` subclass to build our network and intefrace with specific nodes and node types."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from ipywidgets import interact\n",
"import time\n",
"\n",
"# for building application\n",
"from sequence.app.request_app import RequestApp\n",
"from sequence.message import Message\n",
"\n",
"# for building network\n",
"from sequence.topology.router_net_topo import RouterNetTopo"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Custom Application\n",
"\n",
"We may now define our custom application. When receiving an entangled memory, we will announce its reception; we will then use the new `AppMessage` class to communicate results to the other node. The receiving node will wait when receiving an entangled memory. Once the classical message is received from the originator, it will release its local memory to be reused. This mimics the behavior of a teleportation operation."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"START_TIME = 1e12\n",
"\n",
"class TeleportMessage(Message):\n",
" def __init__(self, msg_type, receiver, memo_name: str):\n",
" super().__init__(msg_type, receiver)\n",
" self.memo_name = memo_name\n",
"\n",
"class TeleportApp(RequestApp):\n",
" def __init__(self, node, name, other_name):\n",
" super().__init__(node)\n",
" self.name = name\n",
" self.other_name = other_name\n",
" node.protocols.append(self)\n",
" self.memos_to_measure = {}\n",
" \n",
" # collect metrics:\n",
" self.latency = 0\n",
" self.count = 0\n",
" \n",
" def get_memory(self, info: \"MemoryInfo\") -> None:\n",
" \"\"\"Method to receive entangled memories.\n",
"\n",
" Will check if the received memory is qualified.\n",
" If it's a qualified memory, the application sets memory to RAW state\n",
" and release back to resource manager.\n",
" The counter of entanglement memories, 'memory_counter', is added.\n",
" Otherwise, the application does not modify the state of memory and\n",
" release back to the resource manager.\n",
"\n",
" Args:\n",
" info (MemoryInfo): info on the qualified entangled memory.\n",
" \"\"\"\n",
"\n",
" if info.state != \"ENTANGLED\":\n",
" return\n",
"\n",
" if info.index in self.memo_to_reserve:\n",
" reservation = self.memo_to_reserve[info.index]\n",
" \n",
" if info.remote_node == reservation.responder and info.fidelity >= reservation.fidelity:\n",
" # we are initiator, and want to teleport qubit\n",
" print(\"node {} memory {} entangled with other memory {}\".format(\n",
" self.node.name, info.index, info.remote_memo))\n",
" \n",
" # record metrics\n",
" if self.count == 0:\n",
" # record latency\n",
" pass\n",
" \n",
" # send message to other node\n",
" message = TeleportMessage(None, self.other_name, info.remote_memo)\n",
" \n",
" # reset local memory\n",
" \n",
" elif info.remote_node == reservation.initiator and info.fidelity >= reservation.fidelity:\n",
" # we are responder, and want to receive qubit\n",
" # need to wait on message from sender to correct entanled memory\n",
" self.memos_to_measure[info.memory.name] = info.memory\n",
" \n",
" def received_message(self, src, message):\n",
" memo_name = message.memo_name\n",
" \n",
" print(\"node {} received teleportation message for memory {}\".format(\n",
" self.node.name, memo_name))\n",
" \n",
" # reset local memory\n",
" memory = self.memos_to_measure.pop(memo_name)\n",
" self.node.resource_manager.update(None, memory, \"RAW\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Building the Simulation\n",
"\n",
"We'll now construct the network and add our applications. This example follows the usual process to ensure that all tools function properly:\n",
"1. Create the topology instance for the simulation to manage our network\n",
" - This class will create a simulation timeline\n",
" - This instantiates the Simulation Kernel (see below)\n",
"2. Create the simulated network topology. In this case, we are using an external JSON file to specify nodes and their connectivity.\n",
" - This includes specifying hardware parameters in the `set_parameters` function, defined later\n",
" - This instantiates the Hardware, Entanglement Management, Resource Management, and Network Management modules\n",
"3. Install custom protocols/applications and ensure all are set up properly\n",
" - This instantiates the Application module\n",
"4. Initialize and run the simulation\n",
"5. Collect and display the desired metrics\n",
"\n",
"The JSON file specifies that network nodes should be of type `QuantumRouter`, a node type defined by SeQUeNCe. This will automatically create all necessary hardware and protocol instances on the nodes, and the `Topology` class will automatically generate `BSMNode` instances on the quantum channels between such nodes.\n",
"\n",
"To construct an application, we need:\n",
"- The node to attach the application to\n",
"- The name of the application instance\n",
"- The name of the node to teleport qubits to.\n",
"\n",
"We can get a list of all desired application nodes, in this case routers, from the `Topology` class with the `get_nodes_by_type` method. We then set an application on each one."
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"def test(sim_time=1.5, qc_atten=1e-5):\n",
" \"\"\"\n",
" sim_time: duration of simulation time (s)\n",
" qc_atten: quantum channel attenuation (dB/km)\n",
" \"\"\"\n",
" \n",
" network_config = \"star_network.json\"\n",
" \n",
" # here, we make a new topology using the configuration JSON file.\n",
" # we then modify some of the simulation parameters of the network.\n",
" network_topo = RouterNetTopo(network_config)\n",
" set_parameters(network_topo, sim_time, qc_atten)\n",
" \n",
" # get two end nodes\n",
" start_node_name = \"router1\"\n",
" end_node_name = \"router2\"\n",
" node1 = node2 = None\n",
"\n",
" for router in network_topo.get_nodes_by_type(RouterNetTopo.QUANTUM_ROUTER):\n",
" if router.name == start_node_name:\n",
" node1 = router\n",
" elif router.name == end_node_name:\n",
" node2 = router\n",
" \n",
" start_app_name = \"start_app\"\n",
" end_app_name = \"end_app\"\n",
"\n",
" # create applications\n",
" start_app = None\n",
" end_app = None\n",
" \n",
" # run the simulation\n",
" tl = network_topo.get_timeline()\n",
" tl.show_progress = False\n",
" tl.init()\n",
" \n",
" start_app.start(end_node_name, START_TIME, 2e12, 10, 0.9)\n",
" tick = time.time()\n",
" tl.run()\n",
" \n",
" print(\"\\n\")\n",
" print(\"Execution time: {:.3f} seconds\".format(time.time() - tick))\n",
" \n",
" print(\"\\n\")\n",
" print(\"Latency: {:.3f} s\".format(start_app.latency))\n",
" print(\"Number of entangled memories:\", start_app.count)\n",
" print(\"Average throughput: {:.3f} pairs/s\".format(\n",
" start_app.count / (sim_time - (START_TIME * 1e-12))))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setting parameters\n",
"\n",
"Here we define the `set_parameters` function we used earlier. This function will take a `Topology` as input and change many parameters to desired values. This will be covered in greater detail in workshop 3.\n",
"\n",
"The simulation time limit will be set using the `get_timeline` method.\n",
"\n",
"Quantum memories and detectors are hardware elements, and so parameters are changed by accessing the hardware included with the `QuantumRouter` and `BSMNode` node types. Many complex hardware elements, such as bsm devices or memory arrays, have methods to update parameters for all included hardware elements. This includes `update_memory_params` to change all memories in an array or `update_detector_params` to change all detectors.\n",
"\n",
"We will also set the success probability and swapping degradation of the entanglement swapping protocol. This will be set in the Network management Module (specifically the reservation protocol), as this information is necessary to create and manage the rules for the Resource Management module.\n",
"\n",
"Lastly, we'll update some parameters of the quantum channels. Quantum channels (and, similarly, classical channels) can be accessed from the `Topology` class as the `qchannels` field. Since these are individual hardware elements, we will set the parameters directly."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def set_parameters(topology, simulation_time, attenuation):\n",
" \"\"\"\n",
" simulation_time: duration of simulation time (s)\n",
" attenuation: attenuation on quantum channels (db/m)\n",
" \"\"\"\n",
" \n",
" PS_PER_S = 1e12\n",
" \n",
" # set timeline stop time\n",
" topology.get_timeline().stop_time = (simulation_time * PS_PER_S)\n",
" \n",
" # set memory parameters\n",
" MEMO_FREQ = 2e3\n",
" MEMO_EXPIRE = 0\n",
" MEMO_EFFICIENCY = 1\n",
" MEMO_FIDELITY = 0.9349367588934053\n",
" for node in topology.get_nodes_by_type(RouterNetTopo.QUANTUM_ROUTER):\n",
" memory_array = node.get_components_by_type(\"MemoryArray\")[0]\n",
" memory_array.update_memory_params(\"frequency\", MEMO_FREQ)\n",
" memory_array.update_memory_params(\"coherence_time\", MEMO_EXPIRE)\n",
" memory_array.update_memory_params(\"efficiency\", MEMO_EFFICIENCY)\n",
" memory_array.update_memory_params(\"raw_fidelity\", MEMO_FIDELITY)\n",
"\n",
" # set detector parameters\n",
" DETECTOR_EFFICIENCY = 0.9\n",
" DETECTOR_COUNT_RATE = 5e7\n",
" DETECTOR_RESOLUTION = 100\n",
" for node in topology.get_nodes_by_type(RouterNetTopo.BSM_NODE):\n",
" bsm = node.get_components_by_type(\"SingleAtomBSM\")[0]\n",
" bsm.update_detectors_params(\"efficiency\", DETECTOR_EFFICIENCY)\n",
" bsm.update_detectors_params(\"count_rate\", DETECTOR_COUNT_RATE)\n",
" bsm.update_detectors_params(\"time_resolution\", DETECTOR_RESOLUTION)\n",
" \n",
" # set entanglement swapping parameters\n",
" SWAP_SUCC_PROB = 0.90\n",
" SWAP_DEGRADATION = 0.99\n",
" for node in topology.get_nodes_by_type(RouterNetTopo.QUANTUM_ROUTER):\n",
" node.network_manager.protocol_stack[1].set_swapping_success_rate(SWAP_SUCC_PROB)\n",
" node.network_manager.protocol_stack[1].set_swapping_degradation(SWAP_DEGRADATION)\n",
" \n",
" # set quantum channel parameters\n",
" ATTENUATION = attenuation\n",
" QC_FREQ = 1e11\n",
" for qc in topology.qchannels:\n",
" qc.attenuation = ATTENUATION\n",
" qc.frequency = QC_FREQ"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Running the Simulation\n",
"\n",
"All that is left is to run the simulation with user input. We'll specify:\n",
"\n",
" sim_time: duration of simulation time (s)\n",
" qc_atten: attenuation on quantum channels (dB/m)\n",
"\n",
"Note that different hardware parameters or network topologies may cause the simulation to run for a very long time."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "3015b584b71c4bcd9eaa6db134a806de",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(FloatSlider(value=1.5, description='sim_time', max=2.0, min=1.0), Dropdown(description='…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"<function __main__.test(sim_time=1.5, qc_atten=1e-05)>"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"interact(test, sim_time=(1, 2, 0.1), qc_atten=[0, 1e-5, 2e-5])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "venv",
"language": "python",
"name": "venv"
},
"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.10.2"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading

0 comments on commit da36d3d

Please # to comment.