diff --git a/docs/examples/Qubit operations.ipynb b/docs/examples/Qubit operations.ipynb index 13e7728..ac13063 100644 --- a/docs/examples/Qubit operations.ipynb +++ b/docs/examples/Qubit operations.ipynb @@ -9,7 +9,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "2024-11-27 20:44:26,117 - qm - INFO - Starting session: 4a68c9e2-51d1-4561-80cf-e16b9e54615c\n" + "2024-11-27 20:46:27,774 - qm - INFO - Starting session: 181cc6be-9c4a-4b37-a91e-51deab4fa291\n" ] } ], @@ -73,20 +73,23 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { - "ename": "AttributeError", - "evalue": "'SquarePulse' object has no attribute 'play'", + "ename": "IndexError", + "evalue": "list index out of range", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[5], line 8\u001b[0m\n\u001b[1;32m 6\u001b[0m qubit\u001b[38;5;241m.\u001b[39mimplementations[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mX\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m PulseGateImplementation(pulse\u001b[38;5;241m=\u001b[39mpulse\u001b[38;5;241m.\u001b[39mget_reference())\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m qubit\u001b[38;5;241m.\u001b[39mimplementations[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mX\u001b[39m\u001b[38;5;124m\"\u001b[39m]\u001b[38;5;241m.\u001b[39mid \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mX\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m----> 8\u001b[0m \u001b[43mqubit\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mimplementations\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mX\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mapply\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Repositories/quam/quam/components/implementations/qubit_implementations.py:39\u001b[0m, in \u001b[0;36mPulseGateImplementation.apply\u001b[0;34m(self, amplitude_scale, duration, **kwargs)\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mapply\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39m, amplitude_scale\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, duration\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m---> 39\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpulse\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mplay\u001b[49m(amplitude_scale\u001b[38;5;241m=\u001b[39mamplitude_scale, duration\u001b[38;5;241m=\u001b[39mduration, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", - "File \u001b[0;32m~/Repositories/quam/quam/utils/reference_class.py:38\u001b[0m, in \u001b[0;36mReferenceClass.__getattribute__\u001b[0;34m(self, attr)\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__getattribute__\u001b[39m(\u001b[38;5;28mself\u001b[39m, attr: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Any:\n\u001b[0;32m---> 38\u001b[0m attr_val \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__getattribute__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mattr\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 40\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m attr \u001b[38;5;129;01min\u001b[39;00m [\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m_is_reference\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m_get_referenced_value\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m__post_init__\u001b[39m\u001b[38;5;124m\"\u001b[39m]:\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m attr_val\n", - "\u001b[0;31mAttributeError\u001b[0m: 'SquarePulse' object has no attribute 'play'" + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[4], line 8\u001b[0m\n\u001b[1;32m 6\u001b[0m qubit\u001b[38;5;241m.\u001b[39mimplementations[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mX\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m PulseGateImplementation(pulse\u001b[38;5;241m=\u001b[39mpulse\u001b[38;5;241m.\u001b[39mget_reference())\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m qubit\u001b[38;5;241m.\u001b[39mimplementations[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mX\u001b[39m\u001b[38;5;124m\"\u001b[39m]\u001b[38;5;241m.\u001b[39mid \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mX\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m----> 8\u001b[0m \u001b[43mqubit\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mimplementations\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mX\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mapply\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Repositories/quam/quam/components/implementations/qubit_implementations.py:39\u001b[0m, in \u001b[0;36mPulseGateImplementation.apply\u001b[0;34m(self, amplitude_scale, duration, **kwargs)\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mapply\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39m, amplitude_scale\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, duration\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m---> 39\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpulse\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mplay\u001b[49m\u001b[43m(\u001b[49m\u001b[43mamplitude_scale\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mamplitude_scale\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mduration\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mduration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Repositories/quam/quam/components/pulses.py:232\u001b[0m, in \u001b[0;36mPulse.play\u001b[0;34m(self, amplitude_scale, duration, condition, chirp, truncate, timestamp_stream, continue_chirp, target, validate)\u001b[0m\n\u001b[1;32m 229\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mchannel \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 230\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPulse \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m is not attached to a channel\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m--> 232\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mchannel\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mplay\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 233\u001b[0m \u001b[43m \u001b[49m\u001b[43mpulse_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 234\u001b[0m \u001b[43m \u001b[49m\u001b[43mamplitude_scale\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mamplitude_scale\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 235\u001b[0m \u001b[43m \u001b[49m\u001b[43mduration\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mduration\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 236\u001b[0m \u001b[43m \u001b[49m\u001b[43mcondition\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcondition\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 237\u001b[0m \u001b[43m \u001b[49m\u001b[43mchirp\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchirp\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 238\u001b[0m \u001b[43m \u001b[49m\u001b[43mtruncate\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtruncate\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 239\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestamp_stream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimestamp_stream\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 240\u001b[0m \u001b[43m \u001b[49m\u001b[43mcontinue_chirp\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcontinue_chirp\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 241\u001b[0m \u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtarget\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 242\u001b[0m \u001b[43m \u001b[49m\u001b[43mvalidate\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mvalidate\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 243\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Repositories/quam/quam/components/channels.py:389\u001b[0m, in \u001b[0;36mChannel.play\u001b[0;34m(self, pulse_name, amplitude_scale, duration, condition, chirp, truncate, timestamp_stream, continue_chirp, target, validate)\u001b[0m\n\u001b[1;32m 384\u001b[0m pulse \u001b[38;5;241m=\u001b[39m pulse_name\n\u001b[1;32m 386\u001b[0m \u001b[38;5;66;03m# At the moment, self.name is not defined for Channel because it could\u001b[39;00m\n\u001b[1;32m 387\u001b[0m \u001b[38;5;66;03m# be a property or dataclass field in a subclass.\u001b[39;00m\n\u001b[1;32m 388\u001b[0m \u001b[38;5;66;03m# # TODO Find elegant solution for Channel.name.\u001b[39;00m\n\u001b[0;32m--> 389\u001b[0m \u001b[43mplay\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 390\u001b[0m \u001b[43m \u001b[49m\u001b[43mpulse\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpulse\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 391\u001b[0m \u001b[43m \u001b[49m\u001b[43melement\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 392\u001b[0m \u001b[43m \u001b[49m\u001b[43mduration\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mduration\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 393\u001b[0m \u001b[43m \u001b[49m\u001b[43mcondition\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcondition\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 394\u001b[0m \u001b[43m \u001b[49m\u001b[43mchirp\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchirp\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 395\u001b[0m \u001b[43m \u001b[49m\u001b[43mtruncate\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtruncate\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 396\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimestamp_stream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimestamp_stream\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 397\u001b[0m \u001b[43m \u001b[49m\u001b[43mcontinue_chirp\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcontinue_chirp\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 398\u001b[0m \u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtarget\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 399\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Repositories/quam/.venv/lib/python3.11/site-packages/qm/qua/_dsl.py:170\u001b[0m, in \u001b[0;36mplay\u001b[0;34m(pulse, element, duration, condition, chirp, truncate, timestamp_stream, continue_chirp, target)\u001b[0m\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mplay\u001b[39m(\n\u001b[1;32m 88\u001b[0m pulse: PlayPulseType,\n\u001b[1;32m 89\u001b[0m element: \u001b[38;5;28mstr\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 96\u001b[0m target: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 97\u001b[0m ):\n\u001b[1;32m 98\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124;03m\"\"\"Play a `pulse` based on an 'operation' defined in `element`.\u001b[39;00m\n\u001b[1;32m 99\u001b[0m \n\u001b[1;32m 100\u001b[0m \u001b[38;5;124;03m The pulse will be modified according to the properties of the element\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 168\u001b[0m \u001b[38;5;124;03m ```\u001b[39;00m\n\u001b[1;32m 169\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 170\u001b[0m body \u001b[38;5;241m=\u001b[39m \u001b[43m_get_scope_as_blocks_body\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 171\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m duration \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 172\u001b[0m duration \u001b[38;5;241m=\u001b[39m _unwrap_exp(exp(duration))\n", + "File \u001b[0;32m~/Repositories/quam/.venv/lib/python3.11/site-packages/qm/qua/_dsl.py:1957\u001b[0m, in \u001b[0;36m_get_scope_as_blocks_body\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1955\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_get_scope_as_blocks_body\u001b[39m() \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m _StatementsCollection:\n\u001b[1;32m 1956\u001b[0m \u001b[38;5;28;01mglobal\u001b[39;00m _block_stack\n\u001b[0;32m-> 1957\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28missubclass\u001b[39m(\u001b[38;5;28mtype\u001b[39m(\u001b[43m_block_stack\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m), _BodyScope):\n\u001b[1;32m 1958\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m QmQuaException(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpecting scope with body.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 1959\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _block_stack[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]\u001b[38;5;241m.\u001b[39mbody()\n", + "\u001b[0;31mIndexError\u001b[0m: list index out of range" ] } ], diff --git a/quam/components/implementations/base_implementation.py b/quam/components/implementations/base_implementation.py index 3c3f4d0..af224a5 100644 --- a/quam/components/implementations/base_implementation.py +++ b/quam/components/implementations/base_implementation.py @@ -1,4 +1,5 @@ from abc import ABC, abstractmethod +from typing import Any from quam.core.quam_classes import quam_dataclass, QuamComponent from quam.utils import string_reference as str_ref @@ -23,6 +24,6 @@ def inferred_id(self): ) @abstractmethod - def apply(self, *args, **kwargs): + def apply(self, *args, **kwargs) -> Any: """Applies the operation""" pass diff --git a/quam/components/implementations/qubit_implementations.py b/quam/components/implementations/qubit_implementations.py index 9b75397..81e6e50 100644 --- a/quam/components/implementations/qubit_implementations.py +++ b/quam/components/implementations/qubit_implementations.py @@ -1,4 +1,5 @@ from abc import ABC +from typing import Union from quam.components.implementations.base_implementation import BaseImplementation from quam.components.pulses import Pulse from quam.core import quam_dataclass @@ -30,18 +31,20 @@ class PulseGateImplementation(QubitImplementation): Args: pulse: Name of pulse to be played on qubit. Should be a key in `channel.operations` for one of the qubit's channels - """ - pulse: Pulse + pulse: Union[Pulse, str] def apply(self, *, amplitude_scale=None, duration=None, **kwargs): - self.pulse.play(amplitude_scale=amplitude_scale, duration=duration, **kwargs) + if isinstance(self.pulse, Pulse): + pulse = self.pulse + else: + pulse = self.qubit.get_pulse(self.pulse) + pulse.play(amplitude_scale=amplitude_scale, duration=duration, **kwargs) @quam_dataclass class MeasureImplementation(QubitImplementation): - def apply(self, **kwargs) -> QuaVariableType: return self.qubit.measure(**kwargs) diff --git a/quam/components/quantum_components/qubit.py b/quam/components/quantum_components/qubit.py index 39cd144..dad718a 100644 --- a/quam/components/quantum_components/qubit.py +++ b/quam/components/quantum_components/qubit.py @@ -4,10 +4,12 @@ from qm import qua from quam.components.channels import Channel +from quam.components.pulses import Pulse from quam.core import quam_dataclass, QuamComponent if TYPE_CHECKING: from quam.components.implementations import QubitImplementation + ImplementationType = QubitImplementation else: ImplementationType = Any @@ -37,6 +39,27 @@ def channels(self) -> Dict[str, Channel]: if isinstance(val, Channel) } + def get_pulse(self, pulse_name: str) -> Pulse: + """Returns the pulse with the given name + + Goes through all channels and returns the unique pulse with the given name. + + Raises a ValueError if the pulse is not found or if there are multiple pulses + with the same name. + """ + pulses = [ + pulse + for channel in self.qubit.channels.values() + for key, pulse in channel.operations.items() + if key == pulse_name + ] + if len(pulses) == 0: + raise ValueError(f"Pulse {pulse_name} not found") + elif len(pulses) > 1: + raise ValueError(f"Pulse {pulse_name} is not unique") + else: + return pulses[0] + def align(self, *other_qubits: "Qubit"): """Aligns the execution of all channels of this qubit and all other qubits""" channel_names = [channel.name for channel in self.channels.values()]