@@ -690,14 +690,9 @@ def demultiplex(U, V):
690
690
# Appendix: Gate counts
691
691
# ---------------------
692
692
#
693
- # TODO: VERIFY ROTATION GATE COUNTS
694
- #
695
693
# Before concluding, let us count the gates in the three decompositions we discussed above.
696
694
# We will start with the decompositions as they are and then will comment on optimizations
697
695
# that reduce the CNOT count further.
698
- # We will consider :math:`U(d)` even if the authors of the original decompositions worked with
699
- # :math:`SU(d)`, and we put the global phase into the very first Cartan subgroup of the
700
- # recursive decompositions.
701
696
# We will denote the CNOT (rotation gate) cost for a special unitary on :math:`n` qubits as
702
697
# :math:`c_n` (:math:`r_n`).
703
698
#
@@ -712,7 +707,7 @@ def demultiplex(U, V):
712
707
# part into three CNOTs and three rotation gates.
713
708
# Overall, we thus have :math:`c_2^{\text{KG}}=3` and :math:`r_2^{\text{KG}}=15`.
714
709
#
715
- # For an arbitrary number of qubits :math:`n`, they decompose one special unitary
710
+ # For an arbitrary number of qubits :math:`n`, Khaneja and Glaser decompose one special unitary
716
711
# :math:`U\in SU(2^{n})` into four special unitaries on :math:`n-1` qubits, three
717
712
# :math:`(n-1)`-multiplexed :math:`R_Z` or :math:`R_X` rotations and a number of basis change
718
713
# rotation gates. The multiplexers take :math:`2^{n-1}` CNOT gates and equally many rotation gates
@@ -760,8 +755,7 @@ def demultiplex(U, V):
760
755
# Without any optimizations, the QSD decomposes a unitary on :math:`n` qubits into four unitaries
761
756
# on :math:`n-1` qubits and three :math:`(n-1)`-multiplexed single-qubit :math:`R_Z`
762
757
# and :math:`R_Y` rotations. That is, we find the same behaviour as for the Khaneja-Glaser
763
- # decomposition if we had merged the basis rotations into the unitary blocks that are decomposed
764
- # in the subsequent step.
758
+ # decomposition if we had merged the basis rotations into the smaller unitary blocks.
765
759
# Correspondingly, we get the recursion relation :math:`x_n=4 x_{n-1} +3\cdot 2^{n-1}` for both,
766
760
# the CNOT count and the number of rotation gates. Using the optimal two-qubit decomposition then
767
761
# leads to
@@ -781,7 +775,7 @@ def demultiplex(U, V):
781
775
# :alt: Decomposition of a multiplexed RY rotation on 3 qubits using CZ gates.
782
776
#
783
777
# As the last ``CZ`` gate is (block) diagonal, it can be absorbed into the multiplexed
784
- # :math:`SU(2^{n-1})` operation on the right before decomposing it with the type-A decomposition.
778
+ # :math:`SU(2^{n-1})` operation on the right, before decomposing it with the type-A decomposition.
785
779
# This changes the recursion relation to :math:`c_n = 4 c_{n-1} + 3\cdot 2^{n-1} - 1` and
786
780
# leaves the rotation count unchanged. The solution for the CNOT count is
787
781
# :math:`c_n = \tfrac{13}{24} 4^n -3\cdot 2^{n-1} + \tfrac{1}{3}`.
@@ -795,9 +789,9 @@ def demultiplex(U, V):
795
789
# :width: 75%
796
790
# :alt: Decomposition of a two-qubit unitary with a diagonal and two CNOTs.
797
791
#
798
- # Note that all two-qubit blocks are separated by multiplexer controls, which commute with
799
- # diagonal matrices. Therefore we can start at the right-most block, decompose it into the
800
- # above form, and pull the diagonal through to the left to absorb it into the second two-qubit
792
+ # Note that all two-qubit blocks in the QSD are separated by multiplexer controls, which commute
793
+ # with diagonal matrices. Therefore we can start at the right-most block, decompose it into the
794
+ # above form, and pull the diagonal to the left to absorb it into the second two-qubit
801
795
# block from the right. This block can then be decomposed into the above form again, and the
802
796
# diagonal contribution can be merged into the third block from the right. Continuing this,
803
797
# we find that we can decompose all two-qubit blocks into 2 CNOTs and 14 rotation gates,
@@ -845,6 +839,60 @@ def demultiplex(U, V):
845
839
#
846
840
# c_n^{\text{ZXZ,opt}} &= \tfrac{22}{48} 4^n -3\cdot 2^{n-1} + \tfrac{5}{3},\\
847
841
# r_n^{\text{ZXZ,opt}} &= \tfrac{5}{4} 4^n - 3\cdot 2^{n-1} + 1.
842
+ #
843
+ # We note once more that the transformation into the special block form that is eponymous to
844
+ # the Block-ZXZ decomposition does not yield any CNOT or rotation gate reductions. This is
845
+ # because the controlled gates obtained through the transformation are decomposed like
846
+ # multiplexers, leading to the same cost as before the transformation.
847
+ #
848
+ # To conclude, we plot the CNOT and rotation gate counts, comparing them to their respective
849
+ # lower bounds
850
+ #
851
+ # .. math::
852
+ #
853
+ # c_n^{\text{min}} &= \tfrac{1}{4} (4^n - 3n - 1),\\
854
+ # r_n^{\text{min}} &= 4^n - 1.
855
+ #
856
+ # The former is derived by counting the independent degrees of freedom one can add per CNOT
857
+ # gate in a circuit and equating this with the dimension of the group, :math:`4^n-1`.
858
+ # This dimension then also is the lower bound for the rotation count.
859
+ #
860
+
861
+ n = np .arange (2 , 11 )
862
+ c_n_KG = 11 / 16 * 4 ** n - 3 * 2 ** (n - 1 ) - 2
863
+ r_n_KG = 21 / 16 * 4 ** n - 3 * 2 ** (n - 1 )
864
+
865
+ c_n_QSD = 9 / 16 * 4 ** n - 3 * 2 ** (n - 1 )
866
+ r_n_QSD = 21 / 16 * 4 ** n - 3 * 2 ** (n - 1 )
867
+
868
+ c_n_QSD_opt = 23 / 48 * 4 ** n - 3 * 2 ** (n - 1 ) + 4 / 3
869
+ r_n_QSD_opt = 5 / 4 * 4 ** n - 3 * 2 ** (n - 1 ) + 1
870
+
871
+ c_n_ZXZ = 11 / 24 * 4 ** n - 3 * 2 ** (n - 1 ) + 5 / 3
872
+ r_n_ZXZ = 5 / 4 * 4 ** n - 3 * 2 ** (n - 1 ) + 1
873
+
874
+ c_n_min = 1 / 4 * (4 ** n - 3 * n - 1 )
875
+ r_n_min = 4 ** n - 1
876
+
877
+ all_c_n = [c_n_KG , c_n_QSD , c_n_QSD_opt , c_n_ZXZ , c_n_min ]
878
+ all_r_n = [r_n_KG , r_n_QSD , r_n_QSD_opt , r_n_ZXZ , r_n_min ]
879
+ labels = ["KG" , "QSD" , "QSD, opt" , "Block-ZXZ" , "Lower bound" ]
880
+ colors = ["#DE8900" , "#4D53C8" , "#44ACE8" , "#D7333B" , "#007D33" ]
881
+
882
+
883
+ fig , axs = plt .subplots (1 , 2 , figsize = (12 , 4 ))
884
+ for c_n , r_n , label , color in zip (all_c_n , all_r_n , labels , colors ):
885
+ axs [0 ].plot (n , c_n / 4 ** n , label = label , color = color , lw = 2 )
886
+ ls = ":" if label in ["QSD" , "Block-ZXZ" ] else "-"
887
+ axs [1 ].plot (n , r_n / 4 ** n , label = label , color = color , ls = ls , lw = 2 )
888
+
889
+ ylabels = ["Number of CNOT gates ($/4^n$)" , "Number of rotations ($/4^n$)" ]
890
+ for ax , ylabel in zip (axs , ylabels ):
891
+ ax .legend ()
892
+ ax .set_xlabel ("Number of qubits $n$" )
893
+ ax .set_ylabel (ylabel )
894
+
895
+ ######################################################################
848
896
#
849
897
# About the author
850
898
# ----------------
0 commit comments