|
1 | 1 | ;;;; permutation.lisp
|
| 2 | +;;;; |
| 3 | +;;;; Author: Charles Zhang |
| 4 | + |
| 5 | +(in-package #:cl-quil) |
| 6 | + |
2 | 7 | ;;;; This file implements routines to decompose and synthesize
|
3 | 8 | ;;;; permutation matrices representing classical reversible circuits.
|
4 | 9 |
|
5 |
| -(in-package #:cl-quil) |
6 | 10 |
|
7 | 11 | ;;;; young group decomposition based algorithm for permutation gates
|
8 | 12 |
|
|
63 | 67 | (dotimes (i size)
|
64 | 68 | (assert (= (aref right (aref perm (aref left i)))
|
65 | 69 | (aref old-perm i))))
|
| 70 | + ;; Return g1 and g2 in "mathematical" or "composition" order. |
66 | 71 | (values left right))))
|
67 | 72 |
|
68 | 73 | (defstruct single-target-gate
|
|
73 | 78 | (target (missing-arg) :type fixnum :read-only t))
|
74 | 79 |
|
75 | 80 | (defun single-target-gate-decomposition! (perm)
|
76 |
| - "PERM permutes computational basis to computational basis. This algorithm produces at most 2n-1 single target gates where n is the number of bits, which is nearly optimal." |
77 |
| - (let ((length (length perm))) |
78 |
| - (assert (power-of-two-p length)) |
79 |
| - (let ((n-qubits (1- (integer-length length))) |
80 |
| - (left-gates '()) |
81 |
| - (right-gates '())) |
82 |
| - (dotimes (qubit n-qubits) |
83 |
| - (multiple-value-bind (left right) |
84 |
| - (decompose! perm qubit) |
85 |
| - (flet ((single-target-gate-from-permutation (permutation) |
86 |
| - (multiple-value-bind (truth-table vars) |
87 |
| - (truth-table-minimize-base! |
88 |
| - (make-truth-table n-qubits |
89 |
| - :initial-contents |
90 |
| - (loop for value across permutation |
91 |
| - for row from 0 |
92 |
| - collect (if (= value row) 0 1)))) |
93 |
| - (unless (truth-table-zero-p truth-table) |
94 |
| - (assert (not (member qubit vars))) |
95 |
| - (make-single-target-gate |
96 |
| - :function truth-table |
97 |
| - :control-lines (coerce (sort vars #'<) 'vector) |
98 |
| - :target qubit))))) |
99 |
| - (let ((left-gate (single-target-gate-from-permutation left)) |
100 |
| - (right-gate (single-target-gate-from-permutation right))) |
101 |
| - (when left-gate (push left-gate left-gates)) |
102 |
| - (when right-gate (push right-gate right-gates)))))) |
103 |
| - ;; Combine the left and right gates in the right order. It's |
104 |
| - ;; possible as an additional optimization to merge the |
105 |
| - ;; right-most left gate and the left-most right gate (assuming |
106 |
| - ;; neither is the identity) because they act on the same |
107 |
| - ;; target. In fact, probably any consecutive gates acting on the |
108 |
| - ;; same target can be merged iteratively. |
109 |
| - (nreconc left-gates right-gates)))) |
| 81 | + "PERM permutes computational basis to computational basis. This algorithm produces at most 2n-1 single target gates (acting on qubits numbered 0 to n-1) where n is the number of bits, which is nearly optimal." |
| 82 | + (assert (power-of-two-p (length perm))) |
| 83 | + (let ((n-qubits (ilog2 (length perm))) |
| 84 | + (left-gates '()) |
| 85 | + (right-gates '())) |
| 86 | + (dotimes (index n-qubits) |
| 87 | + (multiple-value-bind (left right) |
| 88 | + (decompose! perm index) |
| 89 | + (flet ((single-target-gate-from-permutation (permutation) |
| 90 | + (multiple-value-bind (truth-table vars) |
| 91 | + (truth-table-minimize-base! |
| 92 | + (make-truth-table n-qubits |
| 93 | + :initial-contents |
| 94 | + (loop :for value :across permutation |
| 95 | + :for row :from 0 |
| 96 | + :collect (if (= value row) 0 1)))) |
| 97 | + (unless (truth-table-zero-p truth-table) |
| 98 | + (assert (not (member index vars))) |
| 99 | + (make-single-target-gate |
| 100 | + :function truth-table |
| 101 | + :control-lines (coerce (sort vars #'<) 'vector) |
| 102 | + :target index))))) |
| 103 | + (let ((left-gate (single-target-gate-from-permutation left)) |
| 104 | + (right-gate (single-target-gate-from-permutation right))) |
| 105 | + (when left-gate (push left-gate left-gates)) |
| 106 | + (when right-gate (push right-gate right-gates)))))) |
| 107 | + ;; Combine the left and right gates in "Quil" order (composition |
| 108 | + ;; applies left-to-right), hence the unintuitive "right" listed |
| 109 | + ;; before "left". |
| 110 | + ;; |
| 111 | + ;; It's possible as an additional optimization to merge the |
| 112 | + ;; right-most left gate and the left-most right gate (assuming |
| 113 | + ;; neither is the identity) because they act on the same |
| 114 | + ;; target. In fact, probably any consecutive gates acting on the |
| 115 | + ;; same target can be merged iteratively. |
| 116 | + (nreconc right-gates left-gates))) |
110 | 117 |
|
111 | 118 | ;;; Synthesize a single target gate by using PPRM (positive polarity
|
112 |
| -;;; Reed-Mueller form). |
113 |
| -(defun simple-single-target-gate-synthesize (gate) |
114 |
| - (let ((control-lines (single-target-gate-control-lines gate)) |
115 |
| - (target (single-target-gate-target gate)) |
116 |
| - (function (single-target-gate-function gate)) |
117 |
| - (circuit '())) |
118 |
| - (let ((esop (truth-table-esop-from-pprm function))) |
119 |
| - (dolist (cube esop) |
120 |
| - (let ((translated-controls '())) |
121 |
| - (dotimes (index (length cube)) |
122 |
| - (let ((trit (aref cube index))) |
123 |
| - (assert (/= trit -1)) ; *PP*RM |
124 |
| - (unless (= trit 0) |
125 |
| - (push (aref control-lines index) translated-controls)))) |
126 |
| - (case (length translated-controls) |
127 |
| - (0 (push (build-gate "X" () target) circuit)) |
128 |
| - (1 (push (build-gate "CNOT" () (first translated-controls) target) circuit)) |
129 |
| - (2 (push (build-gate "CCNOT" () |
130 |
| - (first translated-controls) |
131 |
| - (second translated-controls) |
132 |
| - target) |
133 |
| - circuit)) |
134 |
| - (t |
135 |
| - (push (apply #'build-multiple-controlled-gate |
136 |
| - "X" () (append translated-controls (list target))) |
137 |
| - circuit)))))) |
138 |
| - (nreverse circuit))) |
139 |
| - |
140 |
| -(defun synthesize-permutation (permutation) |
141 |
| - (let ((permutation (make-array (length permutation) :initial-contents permutation))) |
142 |
| - (reduce #'append (mapcar #'simple-single-target-gate-synthesize |
143 |
| - (single-target-gate-decomposition! permutation))))) |
| 119 | +;;; Reed-Mueller) form. |
| 120 | +(defun simple-single-target-gate-synthesize (gate &optional (index->qubit #'identity)) |
| 121 | + "Synthesize a single-target gate GATE, loosely representing the Quil instruction: |
| 122 | +
|
| 123 | + GATE k_0 k_1 ... k_(n-1) |
| 124 | +
|
| 125 | +where |
| 126 | +
|
| 127 | + k_i := INDEX->QUBIT(i) |
| 128 | +
|
| 129 | +By default, INDEX->QUBIT is the identity function, leading to a reverse convention of the standard Quil order of arguments." |
| 130 | + (let ((control-lines (map 'vector index->qubit (single-target-gate-control-lines gate))) |
| 131 | + (target (funcall index->qubit (single-target-gate-target gate))) |
| 132 | + (circuit '())) |
| 133 | + (dolist (cube (truth-table-esop-from-pprm (single-target-gate-function gate))) |
| 134 | + (let ((translated-controls '())) |
| 135 | + (dotimes (index (length cube)) |
| 136 | + (let ((trit (aref cube index))) |
| 137 | + (assert (/= trit -1)) ; *PP*RM |
| 138 | + (unless (= trit 0) |
| 139 | + (push (aref control-lines index) translated-controls)))) |
| 140 | + (case (length translated-controls) |
| 141 | + (0 (push (build-gate "X" () target) circuit)) |
| 142 | + (1 (push (build-gate "CNOT" () (first translated-controls) target) circuit)) |
| 143 | + (2 (push (build-gate "CCNOT" () |
| 144 | + (first translated-controls) |
| 145 | + (second translated-controls) |
| 146 | + target) |
| 147 | + circuit)) |
| 148 | + (t |
| 149 | + (push (apply #'build-multiple-controlled-gate |
| 150 | + "X" () (append translated-controls (list target))) |
| 151 | + circuit))))) |
| 152 | + ;; Return the circuit in "Quil" order (left-to-right). |
| 153 | + circuit)) |
| 154 | + |
| 155 | +(defun synthesize-permutation (permutation qubits) |
| 156 | + "Synthesize the operator represented by the permutation PERMUTATION acting on the vector of qubits QUBITS. |
| 157 | +
|
| 158 | +If permutation represents a matrix mapping the i'th amplitude to the PERMUTATION[i]'th amplitude of a quantum state of qubit indexes {0, 1, ..., n-1}, then QUBITS must be the vector |
| 159 | +
|
| 160 | + #(n-1 n-2 ... 2 1 0) |
| 161 | +
|
| 162 | +in accordance with how Quil interprets a gate application." |
| 163 | + (let ((n (length qubits))) |
| 164 | + (flet ((index->qubit (i) (aref qubits (- n i 1)))) |
| 165 | + (declare (dynamic-extent #'index->qubit)) |
| 166 | + (loop :with permutation := (make-array (length permutation) :initial-contents permutation) |
| 167 | + :for target-gate :in (single-target-gate-decomposition! permutation) |
| 168 | + :nconcing (simple-single-target-gate-synthesize target-gate #'index->qubit))))) |
144 | 169 |
|
145 | 170 | (defun permutation-gate-to-mcx (instr &key context)
|
146 | 171 | "Compile instructions representing permutation gates to n-qubit Toffoli gates."
|
|
153 | 178 | (let* ((perm-gate (funcall
|
154 | 179 | (operator-description-gate-lifter
|
155 | 180 | (application-operator instr))
|
156 |
| - res)) |
157 |
| - (qubits (reverse (application-arguments instr)))) |
| 181 | + res))) |
158 | 182 | (cond
|
159 | 183 | ((and (typep perm-gate 'permutation-gate)
|
160 |
| - (> (length qubits) 2)) |
161 |
| - (let* ((perm (permutation-gate-permutation perm-gate)) |
162 |
| - (code (synthesize-permutation perm)) |
163 |
| - (relabler (lambda (q) |
164 |
| - (setf (qubit-index q) |
165 |
| - (qubit-index (nth (qubit-index q) qubits)))))) |
166 |
| - (map nil (a:rcurry #'cl-quil.frontend::%relabel-qubits relabler) code) |
| 184 | + (> (gate-dimension perm-gate) 4)) ; N.B. Dimension, not arity! |
| 185 | + (let* ((code (synthesize-permutation |
| 186 | + (permutation-gate-permutation perm-gate) |
| 187 | + (map 'vector #'qubit-index (application-arguments instr))))) |
167 | 188 | ;; If synthesis produces a 1 instruction sequence, that
|
168 | 189 | ;; means that the original instruction represents a n-qubit
|
169 | 190 | ;; controlled Toffoli gate, so we didn't do anything and
|
|
0 commit comments