├── .gitignore ├── LICENSE.txt ├── README.md ├── examples ├── entanglement-circuit.pdf ├── entanglement-circuit.png ├── entanglement-circuit.svg ├── entanglement.pdf ├── entanglement.png ├── entanglement.svg ├── interference-circuit.pdf ├── interference-circuit.png ├── interference-circuit.svg ├── interference.pdf ├── interference.png ├── interference.svg ├── no-entanglement-circuit.pdf ├── no-entanglement-circuit.png ├── no-entanglement-circuit.svg ├── no-entanglement.pdf ├── no-entanglement.png ├── no-entanglement.svg ├── no-interference-circuit.pdf ├── no-interference-circuit.png ├── no-interference-circuit.svg ├── no-interference.pdf ├── no-interference.png ├── no-interference.svg └── render_examples.py ├── feynman_path ├── __init__.py ├── __main__.py ├── command.py └── diagram.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /*.egg-info 3 | /build 4 | 5 | # Mac files 6 | .DS_Store 7 | 8 | # cache files 9 | __pycache__/ 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2021 Casey Duckering 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Feynman Path Sum Diagram for Quantum Circuits 2 | 3 | A visualization tool for the Feynman Path Sum applied to quantum circuits. 4 | The [path integral formulation](https://en.wikipedia.org/wiki/Path_integral_formulation) is an interpretation of quantum mechanics that can aid in understanding superposition and interference. 5 | 6 | Path sum: 7 | 8 | 9 | 10 | Circuit diagram: 11 | 12 | 13 | 14 | How to read a path sum diagram: 15 | - Time flows from left to right as gates are executed on qubits. 16 | - Arrows transition from one state to another and traversing the arrows gives a path to an output. 17 | - Two diverging arrows indicate a split into two potential outcomes. 18 | - An orange arrow indicates a negative sign is added to that outcome. 19 | - When two arrows converge, the amplitudes are summed. 20 | - Quantum interference is when positive and negative amplitudes cancel in this sum. 21 | - The rightmost column lists the possible measurement outcomes along with the final probability amplitudes of measuring each outcome. 22 | 23 | See also: [Bloch sphere visualization](https://github.com/cduck/bloch_sphere) 24 | 25 | # Install 26 | 27 | feynman\_path is available on PyPI: 28 | 29 | ```bash 30 | python3 -m pip install feynman_path 31 | ``` 32 | 33 | ## Prerequisites 34 | 35 | Several non-python tools are used to generate the graphics and various output formats. 36 | These non-python dependencies are listed below and platform-specific installation instructions can be found [here](https://github.com/cduck/latextools/#prerequisites). 37 | 38 | - LaTeX: A distribution of LaTeX that provides the `pdflatex` command needs to be installed separately. Used to generate the gate and state labels. 39 | - [pdf2svg](https://github.com/dawbarton/pdf2svg): Used to convert the LaTeX expressions into SVG elements. 40 | - [Inkscape](https://inkscape.org/) (optional): Only required to convert the output to PDF format. 41 | - [Cairo](https://www.cairographics.org/download/) (optional): Only required to convert the output to PNG format. 42 | 43 | ### Ubuntu 44 | 45 | ```bash 46 | sudo apt install texlive pdf2svg inkscape libcairo2 # Or texlive-latex-recommended, or texlive-latex-extra 47 | ``` 48 | 49 | ### macOS 50 | 51 | Using [homebrew](https://brew.sh/): 52 | 53 | ```bash 54 | brew install --cask mactex inkscape 55 | brew install pdf2svg cairo 56 | ``` 57 | 58 | 59 | # Usage 60 | 61 | This package provides a command line tool to generate diagrams. 62 | 63 | ### Examples 64 | ```bash 65 | feynman_path interference 2 h0 cnot0,1 z1 h0 h1 cnot1,0 h1 66 | ``` 67 | 68 | 69 | ```bash 70 | feynman_path interference 2 h0 cnot0,1 z1 h0 h1 cnot1,0 h1 --circuit 71 | ``` 72 | 73 | 74 | ### Command line options 75 | ``` 76 | $ feynman_path -h 77 | usage: feynman_path [-h] [--svg] [--png] [--pdf] [--sequence] [--circuit] 78 | [--scale SCALE] [--verbose] 79 | name n_qubits gate [gate ...] 80 | 81 | Renders a Feynman path sum diagram for a sequence of quantum gates. 82 | 83 | positional arguments: 84 | name The file name to save (excluding file extension) 85 | n_qubits The number of qubits in the quantum circuit 86 | gate List of gates to apply (e.g. h0 z1 cnot0,1) 87 | 88 | optional arguments: 89 | -h, --help show this help message and exit 90 | --svg Save diagram as an SVG image (default) 91 | --png Save diagram as a PNG image 92 | --pdf Save diagram as a PDF document 93 | --sequence Save a sequence of images that build up the diagram from left 94 | to right as -nn.svg/png/pdf 95 | --circuit Save a standard quantum circuit diagram named 96 | -circuit.svg/png/pdf instead of a Feynman path diagram 97 | --scale SCALE Scales the resolution of the diagram when saved as a PNG 98 | --verbose Print extra progress information 99 | ``` 100 | 101 | ### Python Package 102 | feynman\_path also provides a Python 3 package as an alternative to the command line tool. Diagrams can be viewed directly in a Jupyter notebook or saved. 103 | 104 | ```python 105 | import feynman_path 106 | 107 | n_qubits = 3 108 | font = 12 109 | ws_label = 4+0.55*n_qubits # Label width relative to font size 110 | w_time = 60+ws_label*font # Diagram column width 111 | f = feynman_path.Diagram( 112 | n_qubits, font=font, ws_label=ws_label, w_time=w_time) 113 | 114 | f.perform_h(0) 115 | f.perform_cnot(0, 1) 116 | f.perform_z(1) 117 | f.perform_cnot(1, 2, pre_latex=r'\color{red!80!black}') 118 | f.perform_h(0) 119 | f.perform_h(1) 120 | f.perform_cnot(1, 0) 121 | 122 | f.draw() # Display in Jupyter 123 | ``` 124 | ```python 125 | f.draw().save_svg('output.svg') # Save SVG 126 | f.draw().set_pixel_scale(2).save_png('output.png') # Save PNG 127 | import latextools 128 | latextools.svg_to_pdf(f.draw()).save('output.pdf') # Save PDF 129 | ``` 130 | 131 | 132 | See [examples/render\_examples.py](https://github.com/cduck/feynman_path/blob/master/examples/render_examples.py) for more example code. 133 | 134 | # Examples 135 | 136 | ### Using the CNOT gate to entangle qubits 137 | The [CNOT gate](https://en.wikipedia.org/wiki/Controlled_NOT_gate) (⋅–⨁) can be used to entangle two qubits, creating a [Bell pair](https://en.wikipedia.org/wiki/Bell_state), but for certain input qubit states, the CNOT will have no effect. 138 | 139 | **Create a Bell pair by using a CNOT on the |+0⟩ state (q0=|+⟩, q1=|0⟩):** 140 | 141 | 142 | 143 | 144 | 145 | Note the output (rightmost) column is an entangled state: |00⟩+|11⟩ 146 | 147 | ```bash 148 | feynman_path no-entanglement 2 h0 cnot0,1 h0 h1 149 | ``` 150 | 151 | **Fail to create a bell pair by using a CNOT on the |++⟩ state (q0=|+⟩, q1=|+⟩):** 152 | 153 | 154 | 155 | 156 | 157 | ```bash 158 | feynman_path no-entanglement 2 h0 h1 cnot0,1 h0 h1 159 | ``` 160 | 161 | Note the output (rightmost) column is a separable state: |00⟩ 162 | 163 | ### Copying an intermediate qubit state onto an ancilla ruins interference 164 | In classical computing, it is common to inspect intermediate steps of a computation. This can be very useful for debugging. In quantum computing however, this destroys the effect of interference. We can use a [CNOT gate](https://en.wikipedia.org/wiki/Controlled_NOT_gate) (⋅–⨁) to copy an intermediate value onto another qubit to inspect later. Shown below, copying the intermediate value of q1 to q2 changes the output of q0, q1. 165 | 166 | **Original circuit that compute the output q0=1, q1=0:** 167 | 168 | 169 | 170 | 171 | 172 | ```bash 173 | feynman_path interference 2 h0 cnot0,1 z1 h0 h1 cnot1,0 h1 174 | ``` 175 | 176 | **The addition of CNOT1,2 to inspect the intermediate value of q1 changes the output of q0:** 177 | 178 | 179 | 180 | 181 | 182 | Note how the path diagram is the same except the arrows at H1 are now split into the upper and lower halves of the diagram and don't interfere anymore. 183 | 184 | ```bash 185 | feynman_path no-interference 3 h0 cnot0,1 z1 cnot1,2 h0 h1 cnot1,0 h1 186 | ``` 187 | -------------------------------------------------------------------------------- /examples/entanglement-circuit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/entanglement-circuit.pdf -------------------------------------------------------------------------------- /examples/entanglement-circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/entanglement-circuit.png -------------------------------------------------------------------------------- /examples/entanglement-circuit.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /examples/entanglement.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/entanglement.pdf -------------------------------------------------------------------------------- /examples/entanglement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/entanglement.png -------------------------------------------------------------------------------- /examples/entanglement.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | -------------------------------------------------------------------------------- /examples/interference-circuit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/interference-circuit.pdf -------------------------------------------------------------------------------- /examples/interference-circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/interference-circuit.png -------------------------------------------------------------------------------- /examples/interference-circuit.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /examples/interference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/interference.pdf -------------------------------------------------------------------------------- /examples/interference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/interference.png -------------------------------------------------------------------------------- /examples/no-entanglement-circuit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/no-entanglement-circuit.pdf -------------------------------------------------------------------------------- /examples/no-entanglement-circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/no-entanglement-circuit.png -------------------------------------------------------------------------------- /examples/no-entanglement-circuit.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /examples/no-entanglement.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/no-entanglement.pdf -------------------------------------------------------------------------------- /examples/no-entanglement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/no-entanglement.png -------------------------------------------------------------------------------- /examples/no-interference-circuit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/no-interference-circuit.pdf -------------------------------------------------------------------------------- /examples/no-interference-circuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/no-interference-circuit.png -------------------------------------------------------------------------------- /examples/no-interference-circuit.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /examples/no-interference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/no-interference.pdf -------------------------------------------------------------------------------- /examples/no-interference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cduck/feynman_path/d8d98207c5ad531801a0175c4a3e3c4534cffef1/examples/no-interference.png -------------------------------------------------------------------------------- /examples/render_examples.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from feynman_path import command 4 | 5 | 6 | print('\nRendering interference') 7 | #$ feynman_path interference 2 h0 cnot0,1 z1 h0 h1 cnot1,0 h1 8 | # Save all formats and the corresponding circuit diagram 9 | for circuit in [False, True]: 10 | command.main('interference', 11 | 2, 12 | 'h0 cnot0,1 z1 h0 h1 cnot1,0 h1'.split(), 13 | svg=True, 14 | png=True, 15 | pdf=True, 16 | scale=3, 17 | sequence=False, 18 | circuit=circuit) 19 | 20 | 21 | print('\nRendering no-interference') 22 | #$ feynman_path no-interference 3 h0 cnot0,1 z1 cnot1,2 h0 h1 cnot1,0 h1 23 | # Save the circuit diagram 24 | command.main('no-interference', 25 | 3, 26 | 'h0 cnot0,1 z1 cnot1,2 h0 h1 cnot1,0 h1'.split(), 27 | svg=True, 28 | png=True, 29 | pdf=True, 30 | scale=3, 31 | sequence=False, 32 | circuit=True) 33 | # Manually create the path diagram so we can highlight CNOT_12 in red 34 | f = command.draw_diagram(3, []) 35 | f.perform_h(0) 36 | f.perform_cnot(0, 1) 37 | f.perform_z(1) 38 | f.perform_cnot(1, 2, pre_latex=r'\color{red!80!black}') 39 | f.perform_h(0) 40 | f.perform_h(1) 41 | f.perform_cnot(1, 0) 42 | f.perform_h(1) 43 | command.save_formats_from_svg(f.draw(), 'no-interference', 44 | svg=True, png=True, pdf=True, scale=3) 45 | 46 | 47 | print('\nRendering entanglement') 48 | #$ feynman_path no-entanglement 2 h0 cnot0,1 h0 h1 49 | # Save all formats and the corresponding circuit diagram 50 | for circuit in [False, True]: 51 | command.main('entanglement', 52 | 2, 53 | 'h0 cnot0,1 h0 h1'.split(), 54 | svg=True, 55 | png=True, 56 | pdf=True, 57 | scale=3, 58 | sequence=False, 59 | circuit=circuit) 60 | 61 | 62 | print('\nRendering no-entanglement') 63 | #$ feynman_path no-entanglement 2 h0 h1 cnot0,1 h0 h1 64 | # Save all formats and the corresponding circuit diagram 65 | for circuit in [False, True]: 66 | command.main('no-entanglement', 67 | 2, 68 | 'h0 h1 cnot0,1 h0 h1'.split(), 69 | svg=True, 70 | png=True, 71 | pdf=True, 72 | scale=3, 73 | sequence=False, 74 | circuit=circuit) 75 | -------------------------------------------------------------------------------- /feynman_path/__init__.py: -------------------------------------------------------------------------------- 1 | from .diagram import Diagram 2 | -------------------------------------------------------------------------------- /feynman_path/__main__.py: -------------------------------------------------------------------------------- 1 | from .command import run_from_command_line 2 | 3 | if __name__ == '__main__': 4 | run_from_command_line() 5 | -------------------------------------------------------------------------------- /feynman_path/command.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import latextools 3 | 4 | from . import diagram 5 | 6 | 7 | def parse_gate(gate_str): 8 | name = gate_str.translate({ord(digit): '-' for digit in '0123456789'} 9 | ).split('-')[0] 10 | args = tuple(int(arg) for arg in gate_str[len(name):].split(',')) 11 | return name, args 12 | 13 | def draw_diagram(n_qubits, gates): 14 | '''Draw a path sum diagram''' 15 | ws_label = 4+0.55*n_qubits 16 | f = diagram.Diagram( 17 | n_qubits, 18 | font=12, ws_label=ws_label, w_time=60+ws_label*12 19 | ) 20 | 21 | for gate in gates: 22 | name, args = parse_gate(gate) 23 | getattr(f, f'perform_{name}')(*args) 24 | 25 | return f 26 | 27 | def draw_circuit_pdf(n_qubits, gates): 28 | '''Draw a basic circuit diagram using qcircuit in LaTeX''' 29 | lines = [fr'\lstick{{q_{{{i}}}}}' for i in range(n_qubits)] 30 | for gate in gates: 31 | name, args = parse_gate(gate) 32 | if len(args) == 1: 33 | name = name[:1].upper() + name[1:] 34 | for i in range(n_qubits): 35 | if i == args[0]: 36 | lines[i] += fr' & \gate{{{name}}}' 37 | else: 38 | lines[i] += fr' & \qw' 39 | elif len(args) == 2 and name.upper().startswith('C'): 40 | name = name[:1].upper() + name[1:] 41 | targ = (r' & \targ' if name.upper() == 'CNOT' 42 | else fr' & \gate{{{name}}}') 43 | ctrl_len = args[1] - args[0] 44 | for i in range(n_qubits): 45 | if i == args[0]: 46 | lines[i] += fr' & \ctrl{{{ctrl_len}}}' 47 | elif i == args[1]: 48 | lines[i] += targ 49 | else: 50 | lines[i] += fr' & \qw' 51 | else: 52 | raise NotImplementedError( 53 | f'Unsupported circuit diagram gate "{name}"') 54 | for i in range(n_qubits): 55 | lines[i] += r' & \qw \\' 56 | 57 | pdf = latextools.render_qcircuit( 58 | '\n'.join(lines), 59 | lpad=22, rpad=22, tpad=6, bpad=6, r=0.5, c=1, 60 | const_row=True, const_col=True, const_size=True) 61 | return pdf 62 | 63 | def save_formats_from_pdf(p, name, msg='', svg=False, png=False, pdf=False, 64 | scale=1): 65 | if pdf: 66 | p.save(f'{name}.pdf') 67 | print(f'Saved "{name}.pdf"{msg}') 68 | if svg or png: 69 | d = p.as_svg().as_drawing() 70 | if svg: 71 | d.save_svg(f'{name}.svg') 72 | print(f'Saved "{name}.svg"{msg}') 73 | if png: 74 | d.set_pixel_scale(scale) 75 | d.save_png(f'{name}.png') 76 | print(f'Saved "{name}.png"{msg}') 77 | 78 | def save_formats_from_svg(d, name, msg='', svg=False, png=False, pdf=False, 79 | scale=1): 80 | if pdf: 81 | p = latextools.svg_to_pdf(d) 82 | p.save(f'{name}.pdf') 83 | print(f'Saved "{name}.pdf"{msg}') 84 | if svg: 85 | d.save_svg(f'{name}.svg') 86 | print(f'Saved "{name}.svg"{msg}') 87 | if png: 88 | d.set_pixel_scale(scale) 89 | d.save_png(f'{name}.png') 90 | print(f'Saved "{name}.png"{msg}') 91 | 92 | def main(name, n_qubits, gates, svg=False, png=False, pdf=False, sequence=False, 93 | circuit=False, scale=1): 94 | gates_sequence = [gates] 95 | if sequence: 96 | gates_sequence = [gates[:i] for i in range(len(gates)+1)] 97 | 98 | for i, gates in enumerate(gates_sequence): 99 | name_seq = f'{name}-{i:02}' if sequence else name 100 | gates_str = ' '.join(gates) 101 | if circuit: 102 | name_seq += '-circuit' 103 | # Draw a circuit diagram instead 104 | p = draw_circuit_pdf(n_qubits, gates) 105 | save_formats_from_pdf( 106 | p, name_seq, msg=f' with gate sequence "{gates_str}"', 107 | svg=svg, png=png, pdf=pdf, scale=scale 108 | ) 109 | else: 110 | # Draw a path diagram 111 | d = draw_diagram(n_qubits, gates).draw() 112 | save_formats_from_svg( 113 | d, name_seq, msg=f' with gate sequence "{gates_str}"', 114 | svg=svg, png=png, pdf=pdf, scale=scale 115 | ) 116 | 117 | def run_from_command_line(): 118 | parser = argparse.ArgumentParser( 119 | description='Renders a Feynman path sum diagram for a sequence of ' 120 | 'quantum gates.') 121 | parser.add_argument('name', type=str, help= 122 | 'The file name to save (excluding file extension)') 123 | parser.add_argument('n_qubits', type=int, help= 124 | 'The number of qubits in the quantum circuit') 125 | parser.add_argument('gate', type=str, nargs='+', help= 126 | 'List of gates to apply (e.g. h0 z1 cnot0,1)') 127 | parser.add_argument('--svg', action='store_true', help= 128 | 'Save diagram as an SVG image (default)') 129 | parser.add_argument('--png', action='store_true', help= 130 | 'Save diagram as a PNG image') 131 | parser.add_argument('--pdf', action='store_true', help= 132 | 'Save diagram as a PDF document') 133 | parser.add_argument('--sequence', action='store_true', help= 134 | 'Save a sequence of images that build up the diagram from left to right as -nn.svg/png/pdf') 135 | parser.add_argument('--circuit', action='store_true', help= 136 | 'Save a standard quantum circuit diagram named -circuit.svg/png/pdf instead of a Feynman path diagram') 137 | parser.add_argument('--scale', type=float, default=1, help= 138 | 'Scales the resolution of the diagram when saved as a PNG') 139 | parser.add_argument('--verbose', action='store_true', help= 140 | 'Print extra progress information') 141 | 142 | args = parser.parse_args() 143 | # Enable verbose 144 | if args.verbose: 145 | diagram.VERBOSE = True 146 | # If no output formats are selected, default to SVG 147 | svg = args.svg or (not args.png and not args.pdf) 148 | 149 | main(name=args.name, n_qubits=args.n_qubits, gates=args.gate, svg=svg, 150 | png=args.png, pdf=args.pdf, sequence=args.sequence, 151 | circuit=args.circuit, scale=args.scale) 152 | -------------------------------------------------------------------------------- /feynman_path/diagram.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import itertools 3 | import sympy 4 | from sympy.printing.latex import latex 5 | import drawsvg as draw 6 | import latextools 7 | 8 | VERBOSE = False 9 | 10 | 11 | def _disp(svg, msg): 12 | '''Show rendering progress when VERBOSE is True.''' 13 | if not VERBOSE: return svg 14 | try: 15 | from IPython.display import display 16 | except ImportError: 17 | display = print 18 | class DispWrap: 19 | def _repr_svg_(self): return d._repr_svg_() 20 | def __repr__(self): return msg 21 | d = draw.Drawing(50, 20, origin='center') 22 | d.draw(svg, center=True) 23 | display(DispWrap()) 24 | return svg 25 | 26 | @functools.lru_cache(maxsize=None) 27 | def render_cache(latex): 28 | return _disp(latextools.render_snippet( 29 | latex, 30 | latextools.pkg.qcircuit, 31 | latextools.pkg.xcolor, 32 | commands=[latextools.cmd.all_math], 33 | pad=1, 34 | ).as_svg(), 35 | msg=f'Rendered LaTeX element: {latex}') 36 | 37 | def sympy_to_math_mode(sym): 38 | '''Returns the latex math code (without surrounding $) for the sympy symbol. 39 | ''' 40 | return latex(sym, mode='plain', fold_frac_powers=True) 41 | 42 | def render_label(amp_sym, label): 43 | '''Render preset sympy expressions as nice LaTeX equations.''' 44 | presets = { 45 | sympy.sympify(0): '0', 46 | sympy.sympify(1): '1', 47 | sympy.sympify(-1): '-1', 48 | } 49 | if amp_sym in presets: 50 | amp_latex = presets[amp_sym] 51 | else: 52 | # Generate latex for any ±1 / sqrt(2) ** x 53 | amp_latex = '' 54 | give_up = False 55 | amp_sym_orig = amp_sym 56 | if abs(amp_sym) == -amp_sym: 57 | amp_latex += '-' 58 | amp_sym = -amp_sym 59 | elif abs(amp_sym) == amp_sym: 60 | pass 61 | else: 62 | give_up = True 63 | if not give_up: 64 | x = 0 65 | sqrt2 = sympy.sqrt(2) 66 | while amp_sym < 1: 67 | amp_sym = amp_sym * sqrt2 68 | x += 1 69 | if amp_sym != 1: 70 | give_up = True 71 | else: 72 | inner = f'{2**(x//2)}' if x // 2 > 0 else '' 73 | inner += r'\sqrt{2}' if x % 2 == 1 else '' 74 | amp_latex += fr'\frac1{{{inner}}}' 75 | if give_up: 76 | # The expression displayed may not be simplified in the desired way. 77 | amp_latex = sympy_to_math_mode(amp_sym_orig) 78 | return render_cache(fr'${amp_latex}\ket{{{label}}}$') 79 | 80 | 81 | class Diagram: 82 | def __init__(self, n_qubits, init_state=None, 83 | w_time = 120, 84 | h_state = 40, 85 | font = 12, 86 | gate_font = 16, 87 | ws_label = 6, 88 | arrow_space = 1): 89 | if arrow_space > ws_label/2: 90 | arrow_space = ws_label/2 91 | self.w_time = w_time 92 | self.h_state = h_state 93 | self.font = font 94 | self.gate_font = gate_font 95 | self.w_label = self.font * ws_label 96 | self.arrow_off = self.w_label/2 * arrow_space 97 | 98 | self.d = draw.Group() 99 | self.arrows = {} 100 | self.possible_states = [ 101 | ''.join(map(str, qs[::-1])) 102 | for qs in itertools.product(range(2), repeat=n_qubits) 103 | ] 104 | self.num_states = len(self.possible_states) 105 | 106 | if init_state is None: 107 | init_state = {'0'*n_qubits: 1} 108 | self.state_sequence = [init_state] 109 | self.draw_states() 110 | 111 | def draw(self): 112 | w = (len(self.state_sequence)-1) * self.w_time + self.w_label - self.font*0.5 113 | h = (self.num_states-1) * self.h_state + self.font*2 + self.gate_font*3 114 | x = -self.w_label/2 + self.font 115 | y = -(self.num_states-1)/2 * self.h_state - self.font*1.5 116 | d = draw.Drawing(w, h, origin=(x, y)) 117 | d.append(self.d) 118 | return d 119 | def _repr_html_(self): 120 | return self.draw()._repr_html_() 121 | def _repr_svg_(self): 122 | return self.draw()._repr_svg_() 123 | 124 | def state_xy(self, key, time): 125 | state_idx = self.possible_states.index(key) 126 | x = time * self.w_time 127 | y = ((self.num_states-1)/2 - state_idx) * self.h_state 128 | return x, y 129 | 130 | def transition_text(self, g, start_time, label): 131 | x = (start_time+0.5) * self.w_time 132 | y = (self.num_states-1)/2 * self.h_state + self.font/2+self.gate_font*3/2 133 | g.draw(render_cache(fr'${label}$'), 134 | x=x, y=y, scale=self.gate_font/12, center=True) 135 | 136 | def state_text(self, g, time, key, amp=1): 137 | state_idx = self.possible_states.index(key) 138 | x, y = self.state_xy(key, time) 139 | g.draw(render_label(sympy.sympify(amp), key), 140 | x=x+self.w_label/2-self.font*0.2, y=y, scale=self.font/12, center=True, text_anchor='end') 141 | if abs(float(amp)) < 1e-8: 142 | # Draw red X over it 143 | ys = self.font/2*1.4 144 | xs = self.w_label/2*0.7 145 | xf = self.font 146 | g.append(draw.Line(x+xf-xs, y-ys, x+xf+xs, y+ys, stroke='red', stroke_width=1)) 147 | g.append(draw.Line(x+xf-xs, y+ys, x+xf+xs, y-ys, stroke='red', stroke_width=1)) 148 | 149 | def make_arrow(self, color): 150 | key = color 151 | if key in self.arrows: 152 | return self.arrows[key] 153 | arrow = draw.Marker(-0.1, -0.5, 1.1, 0.5, scale=4) 154 | arrow.append(draw.Lines(1, -0.5, 1, 0.5, 0, 0, fill=color, close=True)) 155 | self.arrows[key] = arrow 156 | return arrow 157 | 158 | def straight_arrow(self, g, color, *xy_list, width=1): 159 | rev_xy = xy_list[::-1] 160 | rev_xy = [rev_xy[i+1-2*(i%2)] for i in range(len(rev_xy))] 161 | w = 3 * width 162 | g.append(draw.Line(*rev_xy, 163 | stroke=color, stroke_width=w, fill='none', 164 | # Pull the line behind the arrow 165 | stroke_dasharray=f'0 {w*4/2} 1000000', 166 | marker_start=self.make_arrow(color))) 167 | 168 | def gate_arrow(self, g, time1, key1, key2, amp=1): 169 | w = float(abs(amp)) 170 | x1, y1 = self.state_xy(key1, time1) 171 | x2, y2 = self.state_xy(key2, time1+1) 172 | x1 += self.arrow_off 173 | x2 -= self.arrow_off 174 | xx1 = x1 + self.w_label/2 - self.arrow_off 175 | xx2 = x2 - self.w_label/2 + self.arrow_off 176 | yy1 = y1 + (y2-y1)*(xx1-x1)/(x2-x1) 177 | yy2 = y2 - (y2-y1)*(x2-xx2)/(x2-x1) 178 | color = '#26f' 179 | if abs(float(amp) - abs(float(amp))) >= 1e-8: 180 | color = '#e70' 181 | self.straight_arrow(g, color, xx1, yy1, xx2, yy2, width=w) 182 | 183 | def draw_states(self): 184 | t = len(self.state_sequence)-1 185 | for key, amp in self.state_sequence[-1].items(): 186 | self.state_text(self.d, t, key, amp=amp) 187 | 188 | def add_states(self, new_state): 189 | self.state_sequence.append(new_state) 190 | self.draw_states() 191 | clean_state = { 192 | key: amp 193 | for key, amp in new_state.items() 194 | if abs(float(amp)) >= 1e-8 195 | } 196 | self.state_sequence[-1] = clean_state 197 | 198 | def perform_h(self, q_i, *, pre_latex=f'', name='H'): 199 | new_state = {} 200 | t = len(self.state_sequence)-1 201 | for key, amp in self.state_sequence[-1].items(): 202 | is_one = key[q_i] == '1' 203 | digits = list(key) 204 | digits[q_i] = '0' 205 | zero = ''.join(digits) 206 | digits[q_i] = '1' 207 | one = ''.join(digits) 208 | zero_amp = 1/sympy.sqrt(2) 209 | one_amp = -zero_amp if is_one else zero_amp 210 | self.gate_arrow(self.d, t, key, zero, amp=zero_amp) 211 | self.gate_arrow(self.d, t, key, one, amp=one_amp) 212 | if zero not in new_state: new_state[zero] = 0 213 | if one not in new_state: new_state[one] = 0 214 | new_state[zero] += amp*zero_amp 215 | new_state[one] += amp*one_amp 216 | self.transition_text(self.d, t, f'{pre_latex}{name}_{q_i}') 217 | self.add_states(new_state) 218 | 219 | def perform_cnot(self, qi1, qi2, *, pre_latex=f'', name='CNOT'): 220 | new_state = {} 221 | t = len(self.state_sequence)-1 222 | for key, amp in self.state_sequence[-1].items(): 223 | is_one = key[qi1] == '1' 224 | is_targ_one = key[qi2] == '1' 225 | digits = list(key) 226 | if is_one: 227 | digits[qi2] = '01'[not is_targ_one] 228 | new_key = ''.join(digits) 229 | self.gate_arrow(self.d, t, key, new_key, amp=1) 230 | if new_key not in new_state: new_state[new_key] = 0 231 | new_state[new_key] += amp 232 | self.transition_text(self.d, t, f'{pre_latex}{name}_{{{qi1}{qi2}}}') 233 | self.add_states(new_state) 234 | 235 | def perform_z(self, q_i, *, pre_latex=f'', name='Z'): 236 | new_state = {} 237 | t = len(self.state_sequence)-1 238 | for key, amp in self.state_sequence[-1].items(): 239 | is_one = key[q_i] == '1' 240 | new_amp = -amp if is_one else amp 241 | self.gate_arrow(self.d, t, key, key, amp=new_amp/amp) 242 | if key not in new_state: new_state[key] = 0 243 | new_state[key] += new_amp 244 | self.transition_text(self.d, t, f'{pre_latex}{name}_{{{q_i}}}') 245 | self.add_states(new_state) 246 | 247 | def perform_x(self, q_i, *, pre_latex=f'', name='X'): 248 | new_state = {} 249 | t = len(self.state_sequence)-1 250 | for key, amp in self.state_sequence[-1].items(): 251 | is_one = key[q_i] == '1' 252 | digits = list(key) 253 | digits[q_i] = '01'[not is_one] 254 | new_key = ''.join(digits) 255 | self.gate_arrow(self.d, t, key, new_key, amp=1) 256 | if new_key not in new_state: 257 | new_state[new_key] = 0 258 | new_state[new_key] += amp 259 | self.transition_text(self.d, t, f'{pre_latex}{name}_{{{q_i}}}') 260 | self.add_states(new_state) 261 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | import logging 3 | logger = logging.getLogger(__name__) 4 | 5 | name = 'feynman_path' 6 | package_name = 'feynman_path' 7 | version = '0.2.0' 8 | 9 | try: 10 | with open('README.md', 'r') as f: 11 | long_desc = f.read() 12 | except: 13 | logger.warning('Could not open README.md. long_description will be set to None.') 14 | long_desc = None 15 | 16 | setup( 17 | name = package_name, 18 | packages = find_packages(), 19 | entry_points = { 20 | 'console_scripts': [ 21 | 'feynman_path=feynman_path.command:run_from_command_line', 22 | ]}, 23 | version = version, 24 | description = 'Visualization tool for the Feynman Path Sum applied to quantum circuits', 25 | long_description = long_desc, 26 | long_description_content_type = 'text/markdown', 27 | author = 'Casey Duckering', 28 | #author_email = '', 29 | url = f'https://github.com/cduck/{name}', 30 | download_url = f'https://github.com/cduck/{name}/archive/{version}.tar.gz', 31 | keywords = ['quantum computing', 'feynman path', 'path sum', 'jupyter'], 32 | classifiers = [ 33 | 'License :: OSI Approved :: MIT License', 34 | 'Development Status :: 3 - Alpha', 35 | 'Programming Language :: Python :: 3', 36 | 'Framework :: IPython', 37 | 'Framework :: Jupyter', 38 | ], 39 | install_requires = [ 40 | 'drawSvg~=2.0', 41 | 'latextools~=0.5', 42 | 'sympy~=1.7', 43 | ], 44 | ) 45 | 46 | --------------------------------------------------------------------------------