-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathtutorial.clj
More file actions
2263 lines (1919 loc) · 99.8 KB
/
tutorial.clj
File metadata and controls
2263 lines (1919 loc) · 99.8 KB
1
2
3
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
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;; # QClojure Quantum Computing Tutorial
;; This tutorial will guide you through the basics of quantum computing using
;; [QClojure](https://github.com/lsolbach/qclojure).
;;
;; The tutorial demonstrates the use of the QClojure. It will introduce you
;; to the fascinating world of quantum computing and show you how to use
;; QClojure to create and run quantum programs. It covers
;;
;; * the creation and visualization of quantum states and quantum registers
;; * the application of quantum gates
;; * the creation, visualization and simulation of quantum circuits
;; * the export and import of quantum data
;; * the exchange of quantum circuits with other frameworks
;; * the use of ideal and realistic quantum simulator backends
;; * the optimization of quantum circuits for specific hardware topologies
;; * the use of error mitigation techniques
;; * the description and execution of quantum and hybrid algorithms
;;
;; ## The Tutorial as a Notebook
;; The tutorial is written as a literate programming notebook, in a style
;; called 'Namespace as a Notebook', which means that the code and the
;; documentation are interleaved. You can read the notebook in an editor and
;; run the code snippets in a Clojure REPL.
;;
;; ### Reproducible Notebooks
;; You can also generate documentation with [Clay](https://github.com/scicloj/clay).
;; With Clay a notebook can be rendered to HTML or via [Quarto](https://quarto.org/)
;; to various formats like PDF, revealjs presentations or Github flavoured markdown.
;; Quarto also supports articles, books and websites, so you can easily create an
;; article, book or website from your notebooks.
;;
;; Generating notebooks with Clay always produces **reproducible** results, as
;; the code is in the namespace is executed during the rendering process
;; in a deterministic way. Even with quarto, the code is executed by Clay,
;; not by Quarto or jupyter, so the results are always the same, no matter how often
;; you render the notebook.
;;
;; ## Introduction to Quantum Computing
;; Quantum computing is a fascinating field that combines computer science,
;; physics and math. It allows us to perform computations that are
;; not possible with classical computers. Quantum computers use quantum bits,
;; or [qubits](https://en.wikipedia.org/wiki/Qubit), which can be in a
;; superposition of states. This means that a qubit can be in a state of 0, 1,
;; or both at the same time. Quantum computing is based on the principles of
;; quantum mechanics, which describe the behavior of particles at the quantum
;; level.
;;
;; Quantum computing has the potential to revolutionize many fields, including
;; cryptography, optimization, and machine learning. It can solve certain
;; problems much faster than classical computers, by performing many
;; calculations at once.
;; Quantum Algorithms, such as Shor's algorithm for factoring large numbers
;; and Grover's algorithm for searching unsorted databases, demonstrate the
;; power of quantum computing.
;;
;; Quantum algorithms are defined in terms of quantum gates, which are
;; operations that can be applied to qubits. Quantum gates manipulate the state
;; of qubits and can be combined to create quantum circuits.
;; Quantum circuits are sequences of quantum gates applied to qubits, similar
;; to classical logic circuits.
;;
;; For a general introduction to quantum computing, take a look at
;;
;; * [Quantum Computing](https://en.wikipedia.org/wiki/Quantum_computing)
;; * [But what is quantum computing? (Grover's Algorithm) - 3blue1brown](https://www.youtube.com/watch?v=RQWpF2Gb-gU)
;;
;; ## QClojure
;; The QClojure library provides a Clojure interface to quantum computing concepts.
;; It allows us to create and manipulate quantum states, gates, and circuits in a functional programming style.
;; QClojure can also be used to simulate quantum circuits and, by implementing
;; backends, run them on quantum hardware.
;;
;; QClojure is focused on the core concepts of quantum computing and provides a
;; simple and intuitive API to work with quantum states, gates, and circuits.
;; It also has a comprehensive library of quantum and hybrid algorithms,
;; including Grover's search algorithm, the Quantum Approximate Optimization
;; Algorithm (QAOA), and the Variational Quantum Eigensolver (VQE).
;;
;; QClojure also provides visualization functions to visualize quantum states, circuits
;; and results, making it easier to understand and debug quantum algorithms.
;;
;; QClojure is designed to be extensible, allowing the implementation of backends
;; to run quantum circuits on different quantum hardware. It can also be extended
;; to specialized domains like quantum chemistry or quantum machine learning.
;; Those extensions will be available as separate libraries, to keep the core
;; library focused and lightweight.
;;
;; ### Source Code
;; The source code is available on [GitHub](https://github.com/lsolbach/qclojure).
;;
;; [](https://github.com/lsolbach/qclojure)
;;
;; ### Release Artifacts
;; The release artifacts (JAR files) are available on [Clojars](https://clojars.org/org.soulspace/qclojure).
;; Click on the badge below to go to the Clojars page of the latest release.
;;
;; [](https://clojars.org/org.soulspace/qclojure)
;;
;; QClojure provides citeable releases, so if you use it in your research, you
;; can cite it. Click on the badge below for the DOI of the latest release.
;;
;; [](https://doi.org/10.5281/zenodo.17059552)
;;
;; ### Documentation
;; QClojure provides extensive API documentation, which is available on [CljDoc](https://cljdoc.org/d/org.soulspace/qclojure).
;;
;; [](https://cljdoc.org/d/org.soulspace/qclojure)
;;
;; ### License
;; QClojure is open source and licensed under the Eclipse Public License 1.0.
;;
;; 
;;
;; ### Prerequisites
;; As QClojure is running on Clojure and Clojure itself on the JVM, you need to
;; have the following prerequisites installed on your system:
;;
;; * [JDK 11 or higher](https://openjdk.org/install/)
;; * [Clojure](https://clojure.org/)
;; * [Leiningen](https://leiningen.org/) or [Clojure CLI](https://clojure.org/guides/getting_started)
;; to manage dependencies and run Clojure code.
;;
;; If you are new to Clojure, I recommend reading the
;; [Clojure Getting Started Guide](https://clojure.org/guides/getting_started).
;;
;; ### Usage
;; To use QClojure, you have to include it as a dependency in your Clojure
;; project. Please use the [latest version](https://clojars.org/org.soulspace/qclojure).
;;
;; If you are using Leiningen, add the following dependency to your
;; `project.clj` file:
;;
;; ```clojure
;; [org.soulspace/qclojure "0.24.0"]
;; ```
;;
;; If you are using Clojure CLI, add the following to your `deps.edn` file:
;;
;; ```clojure
;; {:deps {org.soulspace/qclojure {:mvn/version "0.24.0"}}}
;; ```
;;
;; ### Imports
;; We use kindly to visualize the output of our code.
;; Then we import the relevant namespaces for the domain concepts of the
;; QClojure library.
;; The `state` namespace provides functions to create and manipulate quantum
;; states.
;; The `gate` namespace provides functions to create quantum gates.
;; The `circuit` namespace provides functions to create and manipulate quantum
;; circuits.
;;
;; We also import the visualization namespace and the svg renderer.
(ns tutorial
(:require
[fastmath.core :as fm]
[scicloj.kindly.v4.kind :as kind]
[org.soulspace.qclojure.domain.state :as state]
[org.soulspace.qclojure.domain.gate :as gate]
[org.soulspace.qclojure.domain.circuit :as circuit]
[org.soulspace.qclojure.application.visualization :as viz]
[org.soulspace.qclojure.adapter.visualization.ascii :as ascii]
[org.soulspace.qclojure.adapter.visualization.svg :as svg]
[org.soulspace.qclojure.application.hardware-optimization :as hwopt]))
;; Some namespaces, like visualization namespaces contain multimethod
;; implementations. To make sure that the implementations are loaded, we
;; require the namespaces. They will not be used directly in the code, only
;; indirectly by calling the multimethod, so a warning might be shown by
;; your IDE.
;;
;; ## Quantum States
;; A quantum state is a mathematical object that describes the state of a
;; quantum system.
;; In QClojure, quantum states are represented as vectors of complex numbers.
;; The vector of complex numbers represents the amplitudes of the basis states,
;; which represent the possible states of the system.
;; The notation |⟩ is called a "[braket](https://en.wikipedia.org/wiki/Dirac_notation)"
;; and is used to represent a vector in a complex vector space.
;; The Qubit is the basic unit of quantum information, and it can be in a
;; [superposition](https://en.wikipedia.org/wiki/Superposition) of the states
;; |0⟩ and |1⟩.
;; A classic bit can be in one of two states, 0 or 1, but a qubit can be in
;; a superposition of both states.
;; This means that a qubit can represent 0, 1, or both at the same time, with
;; different probabilities.
;;
;; ### Measurement
;; Measurement is the process of extracting classical information from a quantum
;; state. The measurement process is probabilistic, and the probability of
;; measuring a certain state depends on the amplitudes of the basis states in
;; the quantum state.
;; When we measure a quantum state, we collapse it to one of the basis states
;; with a certain probability. After measurement, the quantum state is no longer
;; in a superposition, but in one of the basis states.
;;
;; The result of the measurement is a classical bit, which can be either 0 or 1.
;; The measurement process is a fundamental aspect of quantum mechanics and is
;; described by the [Born rule](https://en.wikipedia.org/wiki/Born_rule).
;; The Born rule states that the probability of measuring a certain state is equal
;; to the square of the amplitude of that state in the quantum state vector.
;;
;; ### Basic Quantum States
;; The *state* namespace defines some basic quantum states.
;; Let's look at the quantum state |0⟩, which is the ground state of a qubit.
state/|0⟩
;; The measured value of a quantum state is probabilistic.
;; We have a probability of measuring the state |0⟩ as 0, and a probability of
;; measuring it as 1.
;; We can visualize the probability distribution of the quantum state |0⟩.
;; QClojure provides several visualization functions in the
;; `org.soulspace.qclojure.application.visualization` namespace.
;; They all take the desired output format as the first argument.
;; We can use the `:ascii` format to generate an ASCII art representation
;; and `:hiccup` format to generate an SVG image.
;; The ASCII format is useful for quick visualizations in the REPL,
;; while the SVG format is more suitable for embedding in documents like
;; tutorials, papers or presentations. We tag the code blocks with
;; `^kind/code` and `^kind/hiccup` to indicate the type of content.
;; With these tags, the Clay notebook renderer can render the output
;; appropriately.
;;
;; Here is the ascii representation of the quantum state |0⟩, which is useful, when you
;; are working in the REPL.
;; It shows that the probability of measuring the state |0⟩ results in 0 is 1,
;; which is certain.
^kind/code
(viz/visualize-quantum-state :ascii state/|0⟩)
;; And this is the SVG representation of the same quantum state.
^kind/hiccup
(viz/visualize-quantum-state :hiccup state/|0⟩)
;; The [Bloch sphere](https://en.wikipedia.org/wiki/Bloch_sphere) is a
;; geometrical representation of quantum states.
;; We can visualize the quantum state |0⟩ as a vector on the Bloch sphere.
;;
;; First the ASCI representation of the Bloch sphere.
^kind/code
(viz/visualize-bloch-sphere :ascii state/|0⟩)
;; And now the Bloch sphere in SVG format of the same quantum state.
^kind/hiccup
(viz/visualize-bloch-sphere :hiccup state/|0⟩)
;; The Bloch sphere representation shows that the state |0⟩ is at the north pole
;; of the sphere.
;;
;; Let's look at another quantum state, the excited state |1⟩.
state/|1⟩
;; We can visualize the probability distribution of the quantum state |1⟩.
^kind/hiccup
(viz/visualize-quantum-state :hiccup state/|1⟩)
;; It shows that the probability of measuring the state |1⟩ results in 1 is 1,
;; which is also certain.
;; The Bloch sphere representation shows that the state |1⟩ is at the south pole
;; of the sphere.
^kind/hiccup
(viz/visualize-bloch-sphere :hiccup state/|1⟩)
;; ### Superposition States
;; Quantum states can also be in a superposition of the ground and excited
;; states.
;; Superposition states are linear combinations of the basic quantum states.
;;
;; Let's look at the quantum state |+⟩, which is a superposition of the ground
;; and excited states.
;; The state |+⟩ is defined as (|0⟩ + |1⟩) / √2.
state/|+⟩
;; We can visualize the probability distribution of the quantum state |+⟩.
^kind/hiccup
(viz/visualize-quantum-state :hiccup state/|+⟩)
;; The Bloch sphere representation shows that the state |+⟩ is on the
;; equator of the sphere, which means, that the probabilities for
;; measuring 0 or 1 are the same.
^kind/hiccup
(viz/visualize-bloch-sphere :hiccup state/|+⟩)
;; The quantum state |-⟩ is another superposition of the ground and
;; excited states. The state |-⟩ is defined as (|0⟩ - |1⟩) / √2.
state/|-⟩
;; We can visualize the probability distribution of the quantum state |-⟩.
^kind/hiccup
(viz/visualize-quantum-state :hiccup state/|-⟩)
;; The Bloch sphere representation shows that the state |-⟩ is also on the
;; equator of the sphere, but pointing in the opposite direction.
^kind/hiccup
(viz/visualize-bloch-sphere :hiccup state/|-⟩)
;; ### Multi-Qubit States and Quantum Registers
;; Tensor products can be used to create multi-qubit states from single-qubit
;; states. For example, the state |00⟩ is the tensor product of two |0⟩ states.
state/|00⟩
;; We can visualize the probability distribution of the quantum state |00⟩.
^kind/hiccup
(viz/visualize-quantum-state :hiccup state/|00⟩)
;; ## Quantum Gates
;; Quantum gates are operations that can be applied to quantum states.
;; They are represented as matrices that act on the quantum states.
;; The *gate* namespace defines several quantum gates.
;;
;; ### Pauli Gates
;; The [Pauli gates](https://en.wikipedia.org/wiki/Pauli_matrices) are a set of
;; quantum gates that can be applied to single qubits.
;;
;; The Pauli-X gate is a quantum gate that flips the state of a qubit around
;; the X axis which swaps the amplitudes of |0⟩ and |1⟩.
gate/pauli-x
;; The Pauli-Y gate is a quantum gate that flips the state of a qubit around
;; the Y axis which swaps the amplitudes of |0⟩ and |1⟩ and also adds a phase.
gate/pauli-y
;; The Pauli-Z gate is a quantum gate that flips the state of a qubit around
;; the Y axis which adds a phase to the state of a qubit.
gate/pauli-z
;; The Pauli gates are self inverse, applying the same gate twice results
;; in the original value.
;;
;; ### Hadamard Gate
;; The [Hadamard gate](https://en.wikipedia.org/wiki/Hadamard_gate) is a
;; quantum gate that creates superposition states.
;; It transforms the state |0⟩ into the state |+⟩ and |1⟩ into the state |-⟩.
;; The Hadamard gate is defined as the matrix:
gate/hadamard
;; We can apply the Hadamard gate to the state |0⟩ to create the superposition
;; state |+⟩.
(def hadamard-state
(gate/h-gate state/|0⟩))
;; We can visualize the probability distribution of the Hadamard state.
^kind/hiccup
(viz/visualize-quantum-state :hiccup hadamard-state)
;; The probability distribution shows that the Hadamard state is in a
;; superposition of the ground and excited states.
^kind/hiccup
(viz/visualize-bloch-sphere :hiccup hadamard-state)
;; The Bloch sphere representation shows that the Hadamard state is on the
;; equator of the sphere.
;;
;; The Hadamard gate is also self inverse, resulting in the input state again
;; if applied twice.
;;
;; ### Phase Gates
;; Phase gates are quantum gates that add a phase to the state of a qubit.
;;
;; The [S gate](https://en.wikipedia.org/wiki/S_gate) is a phase gate that adds
;; a phase of π/2 to the state of a qubit.
gate/s-gate
;; The [S† gate](https://en.wikipedia.org/wiki/S_gate#S%E2%81%BF_gate) is the
;; inverse of the S gate and adds a phase of -π/2 to the state of a qubit.
gate/s-dag-gate
;; The [T gate](https://en.wikipedia.org/wiki/T_gate) is a phase gate that adds
;; a phase of π/4 to the state of a qubit.
gate/t-gate
;; The [T† gate](https://en.wikipedia.org/wiki/T_gate#T%E2%81%BF_gate) is the
;; inverse of the T gate and adds a phase of -π/4 to the state of a qubit.
gate/t-dag-gate
;; ### Rotation Gates
;; Rotation gates are quantum gates that rotate the state of a qubit around
;; the Bloch sphere.
;;
;; The [RX gate](https://en.wikipedia.org/wiki/Rotation_gate#RX_gate) is a
;; rotation gate that rotates the state of a qubit around the X axis of the
;; Bloch sphere.
(gate/rx-gate fm/-QUARTER_PI)
;; The [RY gate](https://en.wikipedia.org/wiki/Rotation_gate#RY_gate) is a
;; rotation gate that rotates the state of a qubit around the Y axis of the
;; Bloch sphere.
(gate/ry-gate fm/-QUARTER_PI)
;; The [RZ gate](https://en.wikipedia.org/wiki/Rotation_gate#RZ_gate) is a
;; rotation gate that rotates the state of a qubit around the Z axis of the
;; Bloch sphere.
(gate/rz-gate fm/-QUARTER_PI)
;; ### Controlled Gates
;; Controlled gates are quantum gates that act on multiple qubits.
;; They are defined as a combination of a control qubit and a target qubit.
;; The control qubit determines whether the target qubit is affected by the gate.
;;
;; The controlled-X gate ([CNOT gate](https://en.wikipedia.org/wiki/CNOT_gate))
;; is a controlled gate that flips the state of the target qubit if the control
;; qubit is in the state |1⟩.
(gate/cnot-gate)
;; The controlled-Y gate is a controlled gate that flips the state of the target
;; qubit and adds a phase if the control qubit is in the state |1⟩.
;;
;; The controlled-Z gate is a controlled gate that adds a phase to the target
;; qubit if the control qubit is in the state |1⟩.
;;
;; ## Quantum Circuits
;; Quantum circuits are sequences of quantum gates applied to quantum states.
;; The *circuit* namespace provides functions to create and manipulate quantum
;; circuits.
;;
;; ### Creating a Quantum Circuit
;; We can create a simple quantum circuit that applies the Hadamard gate to the
;; state |0⟩.
(def simple-circuit
(-> (circuit/create-circuit 1 "Hadamard on qubit 0")
(circuit/h-gate 0)))
;; We can visualize the quantum circuit as ASCII or SVG, like we did with
;; quantum states.
;;
;; Here is the ascii representation of the quantum circuit.
^kind/code
(viz/visualize-circuit :ascii simple-circuit)
;; And this is the SVG representation of the same quantum circuit.
^kind/hiccup
(viz/visualize-circuit :hiccup simple-circuit)
;; The circuit shows that the Hadamard gate is applied to the qubit 0.
;;
;; We can execute the circuit with the `qc/execute-circuit` function
;; on the state |0⟩ to create the Hadamard state.
(def hadamard-circuit-result
(circuit/execute-circuit simple-circuit state/|0⟩))
;; We can visualize the probability distribution of the Hadamard circuit state.
^kind/hiccup
(viz/visualize-quantum-state :hiccup (:final-state hadamard-circuit-result))
;; The probability distribution shows that the Hadamard circuit state is
;; in a superposition of the ground and excited states. It is the same as the
;; Hadamard state we created earlier, but now created by a quantum circuit, not
;; just the application of a single gate on a quantum state.
^kind/hiccup
(viz/visualize-bloch-sphere :hiccup (:final-state hadamard-circuit-result))
;; The *circuit* namespace also has some predefined circuits.
;;
;; For example, the 'qc/bell-state-circuit' creates a circuit that prepares
;; Bell state, which is a two-qubit entangled state.
(def bell-circuit
(circuit/bell-state-circuit))
;; We can visualize the Bell circuit.
^kind/hiccup
(viz/visualize-circuit :hiccup bell-circuit)
;; The Bell circuit shows that the Hadamard gate is applied to the first qubit,
;; followed by a CNOT gate between the first and second qubits.
;; The Bell state is a two-qubit state that is
;;[entangled](https://en.wikipedia.org/wiki/Entanglement).
(def bell-result
(circuit/execute-circuit bell-circuit (state/zero-state 2)))
;; We can visualize the probability distribution of the Bell state.
^kind/hiccup
(viz/visualize-quantum-state :hiccup (:final-state bell-result))
;; The *circuit* namespace also has a predefined circuit for multi-qubit states.
;; This circuit can be used to create entangled states with more than two
;; qubits.
;;
;; For example, the `qc/ghz-circuit` creates a circuit that prepares
;; a Greenberger-Horne-Zeilinger ([GHZ](https://en.wikipedia.org/wiki/Greenberger%E2%80%93Horne%E2%80%93Zeilinger_state))
;; state.
(def ghz-circuit
(circuit/ghz-state-circuit 3))
;; We can visualize the GHZ circuit.
^kind/hiccup
(viz/visualize-circuit :hiccup ghz-circuit)
;; The GHZ circuit shows that the Hadamard gate is applied to the first qubit,
;; followed by CNOT gates between the first and second qubits, and between the
;; first and third qubits. The GHZ state is a multi-qubit state that is entangled.
;;
;; We can apply the GHZ circuit to the state |000⟩ to create the GHZ state.
(def ghz-result
(circuit/execute-circuit ghz-circuit (state/zero-state 3)))
;; We can visualize the probability distribution of the GHZ state.
^kind/hiccup
(viz/visualize-quantum-state :hiccup (:final-state ghz-result))
;; The probability distribution shows that the GHZ state is in a superposition
;; of the states |000⟩ and |111⟩.
;;
;; ## Data Format and I/O
;; Sometimes we want to save quantum circuits or quantum states to disk
;; or read them from disk.
;; This is especially useful if we want to share quantum circuits or states
;; with others or if we want to use quantum circuits or states created
;; in other quantum computing frameworks.
;;
;; QClojure supports various input and output formats for quantum circuits
;; and quantum states. This allows users to easily import and export quantum
;; circuits and states between different quantum computing frameworks and tools.
;; The supported formats include:
;; * Extensible Data Notation (EDN)
;; * JSON (JavaScript Object Notation)
;; * QASM (Quantum Assembly Language)
;;
;; Let's import the I/O namespace providing the API for reading and writing
;; quantum circuits and quantum states.
(require '[org.soulspace.qclojure.adapter.io :as io])
;; Now we define some test data to demonstrate the I/O capabilities.
;; We create a quantum circuit with medium complexity for import and export.
(def test-circuit
(-> (circuit/create-circuit 3 "I/O Test Circuit" "A circuit with medium complexity")
(circuit/h-gate 0)
(circuit/cnot-gate 0 1)
(circuit/t-gate 1)
(circuit/cnot-gate 1 2)
(circuit/measure-operation [0 1 2])))
;; ## EDN Support
;; EDN (Extensible Data Notation) is a data format that is similar to JSON
;; but is more expressive and flexible. It is a subset of Clojure syntax
;; and is used for representing data structures in a human-readable format.
;; QClojure supports EDN format for importing and exporting quantum circuits
;; and quantum states.
(require '[org.soulspace.qclojure.adapter.io.edn :as edn])
;; Let's first write a simple quantum state to disk in EDN format.
(io/export-quantum-state :edn state/|+⟩ "export/plus-state.edn")
;; We can read the quantum state in EDN form back from disk.
(io/import-quantum-state :edn "export/plus-state.edn")
;; ## JSON Support
;; JSON (JavaScript Object Notation) is a lightweight data interchange format
;; that is easy for humans to read and write and easy for machines to parse
;; and generate. It is widely used for data exchange between web applications
;; and servers.
;; QClojure supports JSON format for importing and exporting quantum circuits
;; and quantum states. To use JSON I/O capabilities, we need to require
;; the `io.json` namespace.
(require '[org.soulspace.qclojure.adapter.io.json :as json])
;; The functions for JSON I/O are the same, just with the different format
;; keyword `:json`.
;; Let's write the same quantum state to disk in JSON format.
(io/export-quantum-state :json state/|+⟩ "export/plus-state.json")
;; We can read the quantum state in JSON form back from disk.
(io/import-quantum-state :json "export/plus-state.json")
;; ### OpenQASM Support
;; QASM (Quantum Assembly Language) is a low-level programming language
;; used to describe quantum circuits. It is a standard format for representing
;; quantum circuits and is supported by many quantum computing frameworks.
;; QASM allows us to define quantum gates, measurements, and other operations
;; in a text-based format that can be easily shared and executed on different
;; quantum computing platforms.
;; QASM 3 for example is used as the exchange format for quantum circuits
;; by Amazon Braket. QASM 2 is supported by IBM Quantum and other
;; quantum computing frameworks.
;;
;; QClojure supports QASM 2 and QASM 3 formats, allowing users to import
;; and export quantum circuits in QASM format. It does not support quantum states
;; in QASM format, as QASM is primarily used for representing quantum circuits.
;;
;; Let's require the QASM namespace to explore the QASM I/O capabilities.
(require '[org.soulspace.qclojure.adapter.io.qasm :as qasm])
;; We can export the quantum circuit to QASM 2 format.
(io/export-quantum-circuit :qasm2 test-circuit "export/test-circuit-qasm2.qasm")
;; To see how the QASM 2 output looks like, we can read the file with slurp.
^kind/code
(slurp "export/test-circuit-qasm2.qasm")
;; We can read the quantum circuit in QASM 2 format back from disk.
(io/import-quantum-circuit :qasm2 "export/test-circuit-qasm2.qasm")
;; We can also export the quantum circuit to QASM 3 format.
(io/export-quantum-circuit :qasm3 test-circuit "export/test-circuit-qasm3.qasm")
;; To see how the QASM 3 output looks like, we can read the file with slurp.
^kind/code
(slurp "export/test-circuit-qasm3.qasm")
;; We can read the quantum circuit in QASM 3 format back from disk.
(io/import-quantum-circuit :qasm3 "export/test-circuit-qasm3.qasm")
;;
;; ## Math Backends for Complex Linear Algebra
;; Simulating quantum circuits on a classical computer requires efficient
;; linear algebra operations on complex numbers. QClojure provides a
;; `domain.math.complex-linear-algebra` namespace that abstracts the underlying complex linear algebra
;; implementation. This namespace provides the public API for complex linear
;; algebra operations used in QClojure. It allows to switch between different
;; implementations of complex linear algebra without changing the QClojure code.
;;
;; Protocols define the operations that need to be implemented by a
;; specific complex linear algebra backend implementation:
;;
;; * MatrixAlgebra - defining basic matrix operations like addition, multiplication,
;; products (kronecker/tensor, outer, inner, hadamard), conjugate transpose, etc.
;; * MatrixDecompositions - defining matrix decompositions like
;; singular value decomposition, eigenvalue decomposition, etc.
;; * MatrixFunctions - defining matrix functions like exponentiation, logarithm, square root, etc.
;; * MatrixAnalysis - defining matrix analysis functions like spectral norm, condition number, etc.
;;
;; Currently, QClojure supports two backend implementations:
;;
;; * Fastmath Backend (`:fastmath`), based on FastMath, a high-performance numerical computing
;; library for Clojure. It provides efficient implementations of complex linear
;; algebra operations based on Apache Commons Math.
;; * Pure Clojure Math Backend (`:pure`), based on Clojure Math, a pure Clojure implementation
;; of complex linear algebra operations for educational purpose only.
;;
;; The Fastmath backend is the default backend used by QClojure, as it provides
;; better performance for large quantum states and circuits. The Clojure Math
;; backend should be used only for educational purposes or for small quantum states and
;; circuits.
(require '[org.soulspace.qclojure.domain.math.complex-linear-algebra :as cla])
;; You can switch between the backends by using the `set-backend` function.
;; After switching the backend, all complex linear algebra operations
;; will use the selected backend. Backends may use a different representation
;; for complex numbers and matrices, but the public API handles the conversion
;; between the different representations.
;;
;; The backend can be switched at any time, but it is recommended to set the
;; backend at the beginning of the program, before any quantum states or
;; circuits are created.
;;
;; To switch to the pure Clojure Math backend, use the following code:
(cla/set-backend! :pure)
;; Now, all complex linear algebra operations will use the pure Clojure Math
;; backend.
;;
;; You can switch back to the Fastmath backend by using the following code:
(cla/set-backend! :fastmath)
;; A BLAS/LAPACK (CPU) and OpenCL/CUDA (GPU) enabled backend would be desirable
;; for simulating larger quantum states and circuits, but is not yet available.
;;
;; ## Quantum Devices and Quantum Computing Backends
;; A device represents a quantum computer,also known as a Quantum Processing
;; Unit (QPU), with a certain number of qubits,
;; a native gate set, a topology of coupled qubits and various kinds of noise.
;;
;; Devices are handled by backends, which are responsible for executing
;; quantum circuits on a specific quantum computer or a simulator.
;; Some backends may only support a single device, while others may support
;; multiple devices. A device can represent a real quantum computer or a
;; simulator.
;; Backends that support multiple devices are called multi-device backends.
;; For multi-device backends a specific device can be selected on a backend
;; for the execution of quantum circuits. An example will be shown in the
;; [Hardware Simulator Backend](#hardware-simulator-backend) section below.
;;
;; A quantum backend is an adapter for one or more devices to QClojure.
;; Each backend implements the QuantumBackend protocol. A backend may also
;; implement more specific protocols, like the CloudQuantumBackend, the
;; MultiDeviceBackend or the BatchJobBackend protocol.
;; Backends also provide additional functionality, like optimizing
;; and transforming quantum circuits to run on a specific quantum device.
;;
;; QClojure can be extended with backend implementations to run quantum
;; circuits on real quantum hardware.
;; The *application.backend* namespace contains the protocols to be implemented
;; by a specific backend. A backend can be used to execute a quantum circuit.
(require '[org.soulspace.qclojure.application.backend :as backend])
;; QClojure comes with two simulator backends in the *adapter.backend* that can be used to
;; simulate quantum circuits on a classical computer.
;;
;; * The ideal simulator backend simulates an ideal quantum computer without
;; physical constraints like noise.
;; * The hardware simulator backend simulates a real quantum computer with
;; a native gate set, a topology of coupled qubits and various kinds of noise.
;;
;; Additional backends to access quantum hardware will be available as separate
;; libraries. There is already an experimental implementation for an Amazon
;; Braket backend available in the [qclojure-braket](https://github.com/lsolbach/qclojure-braket)
;; project.
;;
;; Simulating quantum circuits on a classical computer is computationally expensive,
;; as the state space of a quantum system grows exponentially with the number of qubits.
;; Therefore, the simulator backends are limited to a certain number of qubits,
;; depending on the available memory and processing power of the classical computer.
;; The simulator backends are limited to about 20 qubits on a typical desktop computer.
;; Also note that the time to simulate a quantum circuit grows exponentially with the
;; number of qubits and the depth of the circuit.
;; Therefore, simulating quantum circuits with a large number of qubits or a deep
;; circuit can take a long time.
;;
;; ## Ideal Simulator Backend
;; Let's try the ideal simulator first by requiring the `ideal-simulator` namespace.
(require '[org.soulspace.qclojure.adapter.backend.ideal-simulator :as sim])
;; We create the simulator backend with the `create-simulator` function.
(def simulator (sim/create-simulator))
;; Now we can use the simulator to execute the ghz circuit on the simulator.
(backend/execute-circuit simulator (circuit/ghz-state-circuit 3))
;; When executing a circuit on a backend, it will be executed multiple times,
;; because of the probabilistic nature of quantum computing. One execution of the
;; circuit is called a *shot*. The default number of shots is 512, but it can be
;; configured via an options map.
(backend/execute-circuit simulator (circuit/ghz-state-circuit 3) {:shots 10})
;; ## Hardware Simulator Backend
;; Currently existing real quantum hardware has a set of limitations compared
;; to what our ideal simulator supports:
;;
;; * supports only a limited set of native quantum gates
;; * may have a limited topology of coupled qubits
;; * is subject to various kinds of noise
;;
;; This has some consequences for running quantum circuits on real quantum
;; hardware, also known as Quantum Processing Units (QPUs).
;; The limited topology means that not all qubits can be used freely in
;; a multi-qubit gate, e.g. a CNOT gate. If a CNOT gate should be applied to
;; qubits which are not coupled in the topology, represente by a coupling map,
;; Swap gates have to be introduced to 'move' the information to qubits that
;; are coupled, so that the CNOT gate can be applied.
;;
;; The limited native gate set means that our circuit has to be transformed to
;; only use those native gates. This is done by decomposing unsupported gates
;; to supported gates.
;;
;; The hardware simulator backend optimizes and transforms a quantum circuit
;; on submission to the backend, so that it can be executed on the
;; simulated quantum hardware.
;; It optimizes the circuit by reducing the number of gates and the depth
;; of the circuit. It transforms the circuit by decomposing unsupported gates
;; to supported gates and by adding Swap gates to respect the coupling map.
;; Details about the optimization and transformation process are described
;; in the [Circuit Optimization and Transformation](#circuit-optimization-and-transformation)
;; section below.
;;
;; The various kinds of noise affect the results of quantum computations.
;; They can be addressed by error correction, which uses a number of
;; physical qubits to form a logical qubit. On current QPUs with limited
;; qubit counts this is not always an option. Error mitigation strategies try
;; to address the problem mathematically or with more executions.
;;
;; The hardware simulator backend also simulates the noise of a given
;; quantum device, based on a device map provided to the backend,
;; allowing us to study the effects of noise on quantum circuits.
;; It simulates these kinds of noise:
;;
;; * depolarizing noise is a type of noise that randomly flips the state of a
;; qubit with a certain probability.
;; * amplitude damping noise is a type of noise that causes the state of a
;; qubit to decay over time with a certain probability.
;; * bit flip noise is a type of noise that flips the state of a qubit from
;; |0⟩ to |1⟩ or from |1⟩ to |0⟩ with a certain probability.
;; * phase flip noise is a type of noise that flips the phase of the state of
;; a qubit from |0⟩ to |1⟩ or from |1⟩ to |0⟩ with a certain probability.
;; * readout noise is a type of noise that affects the measurement of the
;; state of a qubit, causing the measured value to be incorrect with a
;; certain probability.
;;
;; The hardware simulator backend applies the noise to the quantum states
;; and gates in the circuit, simulating the effects of noise on the quantum
;; computation.
;;
;; Let's try the hardware simulator first by requiring the `hardware-similator` namespace.
(require '[org.soulspace.qclojure.adapter.backend.hardware-simulator :as hwsim])
;; We can instantiate the hardware simulator with the `create-hardware-simulator` function
;; and provide a provide a device map. The device map we use here is derived from the
;; IBM Lagos Quantum Computer.
(def hardware-simulator (hwsim/create-hardware-simulator))
(backend/select-device hardware-simulator (:ibm-lagos hwsim/device-map))
;; The device map shows configurations for the different types of noise,
;; a physical quantum computer can have. All different types of noise contribute
;; to the errors in the measurement.
;; The device map also shows the native gate set and the coupling map of the
;; qubits, which defines the topology of coupled qubits.
;;
;; Now we can use the simulator to execute the ghz circuit on the simulator.
;; Because we use a hardware simulator simulating noise, we may measure wrong
;; answers.
(def lagos-50-result (backend/execute-circuit hardware-simulator (circuit/ghz-state-circuit 3) {:shots 50}))
lagos-50-result
^kind/hiccup
(viz/visualize-quantum-state :hiccup (get-in lagos-50-result [:results :final-state ]))
;; We see, that not all measurements measure the states |000⟩ and |111⟩,
;; even though those states should have the highest counts. The other states
;; should have a distinctively lower count. But if you use to few shots, you
;; could be unlucky and measure the wrong answers. The probability to measure
;; the wrong answers gets lower by increasing the number of shots.
(def lagos-10k-result (backend/execute-circuit hardware-simulator (circuit/ghz-state-circuit 3) {:shots 10000}))
lagos-10k-result
;; With 10000 shots, the difference of the counts of the correct answers
;; and the counts of the wrong answers should be quite significant.
^kind/hiccup
(viz/visualize-measurement-histogram :hiccup (get-in lagos-10k-result [:results :measurement-results]))
;; We can also use the hardware simulator with a different device map, e.g.
;; for an IonQ Forte quantum computer.
;; Let's select IonQ Forte device for the simulation.
(backend/select-device hardware-simulator (:ionq-forte hwsim/device-map))
;; We now execute the GHZ circuit on this simulator with 10000 shots and
;; compare the results with the IBM Lagos simulation.
(def forte-10k-result (backend/execute-circuit hardware-simulator (circuit/ghz-state-circuit 3) {:shots 10000}))
forte-10k-result
;; Compared to the IBM Lagos simulation, the IonQ Forte simulation should have
;; distinctly lower noise and thus a higher count for the correct answers.
^kind/hiccup
(viz/visualize-measurement-histogram :hiccup (get-in forte-10k-result [:results :measurement-results]))
;; You can also create your own device profiles by defining a device map
;; with the required parameters. You can then use this device map to create
;; a hardware simulator backend.
;; A device map may not have all parameters defined. In this case some features
;; may not be used, e.g. error mitigation techniques.
;; If you provide a device map with no native-gates, coupling and noise model
;; defined, the hardware simulator will behave like the ideal simulator.
;; You can also modify an existing device map to create a new device map for
;; testing specific aspects or scenarios.
;;
;; ## Circuit Optimization and Transformation
;; Quantum circuits can be optimized and transformed to improve their performance
;; and to run on specific quantum hardware. This transformation is also called
;; *transpilation*. QClojure provides a set of optimization and transformation
;; techniques that can be applied to quantum circuits.
;;
;; ### Gate Optimization
;; Gate optimization is a technique used to reduce the number of gates in a
;; quantum circuit. It is based on the idea that some gates can be combined
;; or eliminated without changing the overall functionality of the circuit.
;; Gate optimization can be applied to quantum circuits to improve their
;; performance and to reduce the effects of noise.
;; For example, consecutive Pauli and Hadamard gates can be eliminated, as they
;; are self-inverse. QClojure implements some gate optimization techniques:
;;
;; * Gate Cancellation - eliminates consecutive gates that cancel each other out.
;; * Rotation Folding - combines consecutive rotation gates into a single rotation gate.
;;
;; ### Qubit Optimization
;; Qubit optimization is a technique used to reduce the number of qubits in
;; a quantum circuit. It is based on the idea that some qubits can be eliminated
;; without changing the overall functionality of the circuit. The simplest case
;; is to eliminate qubits that are not used in the circuit.
;;
;; ### Error Correction
;; Error correction is a technique used to protect quantum information from
;; errors due to noise and decoherence. It is based on the idea of encoding
;; quantum information in a way that allows errors to be detected and corrected.
;; Error correction can be applied to quantum circuits to improve their
;; performance and to reduce the effects of noise. The encoded circuit will
;; use more physical qubits to form logical qubits, so it is not always an
;; option on current QPUs with limited qubit counts.
;; QClojure has a stabilizer framework with these error correction codes implemented:
;;
;; * Bit Flip Code - a simple error correction code that can correct a single
;; bit flip error.
;; * Phase Flip Code - a simple error correction code that can correct a single
;; phase flip error.
;; * Shor Code - a more complex error correction code that can correct both
;; bit flip and phase flip errors.
;; * Steane Code - a more complex error correction code that can correct both
;; bit flip and phase flip errors.
;; * 5-Qubit Code - the smallest code that can correct an arbitrary single-qubit error.
;;
;; ### Topology Optimization
;; Topology optimization is a technique used to transform a quantum circuit
;; to run on specific quantum hardware. Quantum hardware has a limited topology
;; of coupled qubits, which means that not all qubits can be used freely in
;; a multi-qubit gate, e.g. a CNOT gate. If a CNOT gate should be applied to
;; qubits which are not coupled in the topology, represented by a coupling map,
;; Swap gates have to be introduced to 'move' the information to qubits that
;; are coupled, so that the CNOT gate can be applied. Topology optimization
;; can be applied to quantum circuits to transform them to run on specific
;; quantum hardware.
;;
;; ### Gate Decomposition
;; Gate decomposition is a technique used to transform a quantum circuit
;; to use only a limited set of native quantum gates. Quantum hardware supports
;; only a limited set of native quantum gates, which means that some gates
;; in a quantum circuit may not be supported by the hardware. Gate decomposition
;; can be applied to quantum circuits to transform them to use only the
;; native gates supported by the hardware. For example, a Toffoli gate can be
;; decomposed into a series of CNOT and single-qubit gates.
;;
;; ### The Optimization Pipeline
;; QClojure provides an optimization pipeline that can be used to apply
;; these optimization and transformation techniques to a quantum circuit.
;; The optimization pipeline will apply the techniques in a specific order
;; to optimize and transform the quantum circuit for a specific hardware.
;;
;; The optimization pipeline is used in the backends, e.g. the hardware
;; simulator backend, on circuit submission to optimize and transform the
;; quantum circuit before executing it on the backend. So normally there is no
;; need to call the optimization pipeline directly.
;;