|
283 | 283 | "source": [ |
284 | 284 | "## `QDType`, `CDType`, and `QCDType`\n", |
285 | 285 | "\n", |
286 | | - "Quantum variables are essential when authoring quantum programs, but we live in a classical world. Measuring a qubit yields a classical bit, and a program can do classical branching (choosing which quantum operations to execute based on a classical bit). Each data type we've seen so far is a quantum data type and inherits from `QDType`. " |
| 286 | + "Quantum variables are essential when authoring quantum programs, but we live in a classical world. Measuring a qubit yields a classical bit, and a program can do classical branching (choosing which quantum operations to execute based on a classical bit). Each data type we've seen so far is a quantum data type and inherits from `QDType`. There is a more general base class: `QCDType` that includes both quantum and classical data types. Classical data types inherit from `CDType`" |
287 | 287 | ] |
288 | 288 | }, |
289 | 289 | { |
290 | 290 | "cell_type": "code", |
291 | 291 | "execution_count": null, |
292 | | - "id": "06c5c158-555b-48cd-b612-e00d03b82f70", |
| 292 | + "id": "25191c43-18d1-49fd-9a76-363cc3b7548c", |
293 | 293 | "metadata": {}, |
294 | 294 | "outputs": [], |
295 | 295 | "source": [ |
296 | | - "from qualtran import QDType\n", |
297 | | - "\n", |
298 | | - "print(\"QBit() is QDType:\", isinstance(QBit(), QDType), \"; num_qubits =\", QBit().num_qubits)\n", |
299 | | - "print(\"QUInt(4) is QDType:\", isinstance(QUInt(4), QDType), \"; num_qubits =\", QUInt(4).num_qubits)" |
| 296 | + "# Make a list of all the built-in data types\n", |
| 297 | + "import qualtran.dtype as qdt\n", |
| 298 | + "\n", |
| 299 | + "dtypes = [\n", |
| 300 | + " qdt.QBit(), qdt.CBit(),\n", |
| 301 | + " qdt.QAny(8),\n", |
| 302 | + " qdt.QInt(8), qdt.CInt(8),\n", |
| 303 | + " qdt.QIntOnesComp(8), qdt.CIntOnesComp(8),\n", |
| 304 | + " qdt.QUInt(8), qdt.CUInt(8),\n", |
| 305 | + " qdt.BQUInt(8, 230), qdt.BCUInt(8, 230),\n", |
| 306 | + " qdt.QFxp(8, 2), qdt.CFxp(8, 2),\n", |
| 307 | + " qdt.QMontgomeryUInt(8, 227), qdt.CMontgomeryUInt(8, 227),\n", |
| 308 | + " qdt.QGF(3, 4), qdt.CGF(3, 4),\n", |
| 309 | + " qdt.QGFPoly(4, qdt.QGF(2,2)), qdt.CGFPoly(4, qdt.CGF(2,2)),\n", |
| 310 | + "]" |
300 | 311 | ] |
301 | 312 | }, |
302 | 313 | { |
303 | 314 | "cell_type": "markdown", |
304 | | - "id": "c434a68e-b691-4a35-bc81-49b7159728f8", |
| 315 | + "id": "701ebb85-8e44-4456-95da-ef2ead979c5f", |
305 | 316 | "metadata": {}, |
306 | 317 | "source": [ |
307 | | - "There is a more general base class: `QCDType` that includes both quantum and classical data types. Classical data types inherit from `CDType`" |
| 318 | + "### Table of data type properties" |
308 | 319 | ] |
309 | 320 | }, |
310 | 321 | { |
311 | 322 | "cell_type": "code", |
312 | 323 | "execution_count": null, |
313 | | - "id": "c983e4cb-ac84-497b-883f-3a71abf6878f", |
| 324 | + "id": "7c38eb9b-60d5-4d0c-b282-19f2638bc483", |
314 | 325 | "metadata": {}, |
315 | 326 | "outputs": [], |
316 | 327 | "source": [ |
317 | | - "from qualtran import QCDType, QDType, CDType, CBit\n", |
318 | | - "\n", |
319 | | - "dtypes = [QBit(), QUInt(4), CBit()]\n", |
320 | | - "\n", |
321 | | - "print(f\"{'dtype':10} {'QCDType?':9s} {'QDType?':9s} {'CDType?':9s}\"\n", |
322 | | - " f\"{'bits':>6s} {'qubits':>6s} {'cbits':>6s}\"\n", |
323 | | - " )\n", |
| 328 | + "print(f\"{'dtype':23} {'QCDType?':9s} \"\n", |
| 329 | + " f\"{'QDType?':9s} {'CDType?':9s} \"\n", |
| 330 | + " f\"{'bits':>6s} {'qubits':>6s} {'cbits':>6s}\")\n", |
| 331 | + "print(\"-\"*80)\n", |
| 332 | + "for dtype in dtypes:\n", |
| 333 | + " print(f\"{dtype!s:23} {isinstance(dtype, qdt.QCDType)!s:9} \"\n", |
| 334 | + " f\"{isinstance(dtype, qdt.QDType)!s:9} {isinstance(dtype, qdt.CDType)!s:9}\"\n", |
| 335 | + " f\"{dtype.num_bits:6d} {dtype.num_qubits:6d} {dtype.num_cbits:6d}\")" |
| 336 | + ] |
| 337 | + }, |
| 338 | + { |
| 339 | + "cell_type": "markdown", |
| 340 | + "id": "c2089b62-36ce-4c90-b794-4e5e8338de47", |
| 341 | + "metadata": {}, |
| 342 | + "source": [ |
| 343 | + "### Table of data type encoding examples" |
| 344 | + ] |
| 345 | + }, |
| 346 | + { |
| 347 | + "cell_type": "code", |
| 348 | + "execution_count": null, |
| 349 | + "id": "dd0c1fd9-94d3-45fd-8766-c18615fc5123", |
| 350 | + "metadata": {}, |
| 351 | + "outputs": [], |
| 352 | + "source": [ |
| 353 | + "print(f\"{'dtype':23} {'val':>6s} \"\n", |
| 354 | + " f\"{'encoding':s}\")\n", |
324 | 355 | "print(\"-\"*60)\n", |
325 | 356 | "for dtype in dtypes:\n", |
326 | | - " print(f\"{dtype!s:10} {isinstance(dtype, QCDType)!s:9} {isinstance(dtype, QDType)!s:9} {isinstance(dtype, CDType)!s:9}\"\n", |
327 | | - " f\"{dtype.num_bits:6d} {dtype.num_qubits:6d} {dtype.num_cbits:6d}\"\n", |
328 | | - " )" |
| 357 | + " if isinstance(dtype, QAny):\n", |
| 358 | + " print(f\"{dtype!s:23} {'':6s} [opaque encoding]\")\n", |
| 359 | + " continue\n", |
| 360 | + " vals = list(dtype.get_classical_domain())\n", |
| 361 | + "\n", |
| 362 | + " val = vals[0] # take the minimum\n", |
| 363 | + " val_bits = dtype.to_bits(val)\n", |
| 364 | + " val_bits_str = ','.join(str(bit) for bit in val_bits)\n", |
| 365 | + " print(f\"{dtype!s:23} {val!s:>6} {val_bits_str}\")\n", |
| 366 | + "\n", |
| 367 | + " val = vals[-1] # take the maximum\n", |
| 368 | + " val_bits = dtype.to_bits(val)\n", |
| 369 | + " val_bits_str = ','.join(str(bit) for bit in val_bits)\n", |
| 370 | + " print(f\"{'':23} {val!s:>6} {val_bits_str}\")" |
| 371 | + ] |
| 372 | + }, |
| 373 | + { |
| 374 | + "cell_type": "markdown", |
| 375 | + "id": "a40933a4-1656-4a5a-b352-a09daf626518", |
| 376 | + "metadata": {}, |
| 377 | + "source": [ |
| 378 | + "## Adding a new type\n", |
| 379 | + "\n", |
| 380 | + "You can add custom types by implementing the `_BitEncoding` interface and defining a light-weight `QDType` and/or `CDType`.\n", |
| 381 | + "\n", |
| 382 | + " 1. Define a class that implements the `BitEncoding[T]` abstract interface. the generic `T` should be the type of the analogous Python classical type. For example, `_Int` inherits from `BitEncoding[int]` and defines methods `to_bits`, `from_bits`, etc.\n", |
| 383 | + " 2. Define a _quantum_ data type class that inherits from the `QDType[T]` base class. Override the abstract property `_bit_encoding` to return an instance of the bit encoding class you defined before. For example, `QInt` inherits from `QDType[int]` and its `_bit_encoding` property returns `_Int(self.bitsize)`. \n", |
| 384 | + " 3. Perform an analogous step to deinfe a _classical_ data type class that inherits from `CDType[T]` (but returns the same `BitEncoding` implementation). For example, `CInt` inherits from `CDType[int]` and its `_bit_encoding` property returns `_Int(self.bitsize)`. " |
329 | 385 | ] |
330 | 386 | } |
331 | 387 | ], |
|
345 | 401 | "name": "python", |
346 | 402 | "nbconvert_exporter": "python", |
347 | 403 | "pygments_lexer": "ipython3", |
348 | | - "version": "3.11.8" |
| 404 | + "version": "3.13.9" |
349 | 405 | } |
350 | 406 | }, |
351 | 407 | "nbformat": 4, |
|
0 commit comments