|
| 1 | +;;;; error-qvm.lisp |
| 2 | +;;;; |
| 3 | +;;;; This file implements an efficient QVM which tracks the propagation of Pauli |
| 4 | +;;;; errors through a CNOT-dihedral circuit which, in the absence of errors, is |
| 5 | +;;;; always meant to MEASURE zeroes. For example, surface code cycles for the |
| 6 | +;;;; usual toric code have this property. |
| 7 | + |
| 8 | +(in-package #:qvm.error) |
| 9 | + |
| 10 | +(defclass error-qvm (fowler-qvm classical-memory-mixin) |
| 11 | + ((X-vector |
| 12 | + :accessor error-qvm-X-vector |
| 13 | + :type simple-bit-vector |
| 14 | + :documentation "A bit-vector which tracks whether this qubit has experienced an X-error.") |
| 15 | + (Z-vector |
| 16 | + :accessor error-qvm-Z-vector |
| 17 | + :type simple-bit-vector |
| 18 | + :documentation "A bit-vector which tracks whether this qubit has experienced a Z-error.") |
| 19 | + (num-qubits |
| 20 | + :type unsigned-byte |
| 21 | + :reader error-qvm-num-qubits |
| 22 | + :initarg :num-qubits)) |
| 23 | + (:documentation "A noisy QVM that can efficiently the propagation of Pauli errors through gates drawn from the CNOT-dihedral group of order 8. See FOWLER-QVM for a description of the noise model and parameters.")) |
| 24 | + |
| 25 | +(defun make-error-qvm (num-qubits |
| 26 | + &key |
| 27 | + (classical-memory-model quil::**empty-memory-model**) |
| 28 | + (noise-probability 0.0d0) |
| 29 | + (noise-class 0)) |
| 30 | + "Constructs a fresh instance of a specialized QVM which efficiently simulates Pauli error propagation through CNOT-dihedral circuits. |
| 31 | +
|
| 32 | +See ERROR-QVM for a description of the noise model and noise keyword arguments." |
| 33 | + (check-type num-qubits unsigned-byte) |
| 34 | + (check-type classical-memory-model quil:memory-model) |
| 35 | + (let* ((subsystem (make-instance 'classical-memory-subsystem |
| 36 | + :classical-memory-model |
| 37 | + classical-memory-model)) |
| 38 | + (qvm (make-instance 'error-qvm |
| 39 | + :num-qubits num-qubits |
| 40 | + :classical-memory-subsystem subsystem |
| 41 | + :noise-probability noise-probability |
| 42 | + :noise-class noise-class))) |
| 43 | + (setf (error-qvm-X-vector qvm) (make-array num-qubits :element-type 'bit :initial-element 0) |
| 44 | + (error-qvm-Z-vector qvm) (make-array num-qubits :element-type 'bit :initial-element 0)) |
| 45 | + qvm)) |
| 46 | + |
| 47 | +(defmethod number-of-qubits ((qvm error-qvm)) |
| 48 | + (error-qvm-num-qubits qvm)) |
| 49 | + |
| 50 | +;;;;;;;;;;;;;;;;;;;;;;;;; TRANSITION Methods ;;;;;;;;;;;;;;;;;;;;;;;;; |
| 51 | + |
| 52 | +(defmethod measure ((qvm error-qvm) q) |
| 53 | + (values qvm (aref (error-qvm-X-vector qvm) q))) |
| 54 | + |
| 55 | +(defmethod transition ((qvm error-qvm) (instr quil:reset)) |
| 56 | + (let ((num-qubits (number-of-qubits qvm))) |
| 57 | + (setf (error-qvm-X-vector qvm) (make-array num-qubits :element-type 'bit :initial-element 0) |
| 58 | + (error-qvm-Z-vector qvm) (make-array num-qubits :element-type 'bit :initial-element 0)) |
| 59 | + (incf (qvm::pc qvm)) |
| 60 | + qvm)) |
| 61 | + |
| 62 | +(defmethod transition ((qvm error-qvm) (instr quil:reset-qubit)) |
| 63 | + (let ((index (quil:qubit-index (quil:reset-qubit-target instr)))) |
| 64 | + (setf (aref (error-qvm-X-vector qvm) index) 0 |
| 65 | + (aref (error-qvm-Z-vector qvm) index) 0)) |
| 66 | + (incf (qvm::pc qvm)) |
| 67 | + qvm) |
| 68 | + |
| 69 | +(defmethod transition ((qvm error-qvm) (instr quil:measure)) |
| 70 | + (incf (qvm::pc qvm)) |
| 71 | + (qvm::measure-and-store qvm |
| 72 | + (quil:qubit-index (quil:measurement-qubit instr)) |
| 73 | + (quil:measure-address instr))) |
| 74 | + |
| 75 | +(defmethod transition ((qvm error-qvm) (instr quil:measure-discard)) |
| 76 | + (incf (qvm::pc qvm)) |
| 77 | + (measure qvm (quil:qubit-index (quil:measurement-qubit instr)))) |
| 78 | + |
| 79 | +(defmethod transition ((qvm error-qvm) (instr quil:gate-application)) |
| 80 | + (check-type (quil:application-operator instr) quil:named-operator) |
| 81 | + (adt:with-data (quil:named-operator name) (quil:application-operator instr) |
| 82 | + (cond |
| 83 | + ;; intentional toggles do nothing |
| 84 | + ((or (string= "X" name) |
| 85 | + (string= "Y" name) |
| 86 | + (string= "Z" name) |
| 87 | + (string= "I" name)) |
| 88 | + nil) |
| 89 | + ;; hadamards trade X and Z |
| 90 | + ((string= "H" name) |
| 91 | + (let* ((index (quil:qubit-index (first (quil:application-arguments instr)))) |
| 92 | + (X (aref (error-qvm-X-vector qvm) index)) |
| 93 | + (Z (aref (error-qvm-Z-vector qvm) index))) |
| 94 | + (setf (aref (error-qvm-X-vector qvm) index) Z |
| 95 | + (aref (error-qvm-Z-vector qvm) index) X))) |
| 96 | + ;; CNOTs either transmit or replicate pauli errors. |
| 97 | + ;; Xs and Zs replicate when present on control and target respectively |
| 98 | + ((string= "CNOT" name) |
| 99 | + (let* ((control (quil:qubit-index (first (quil:application-arguments instr)))) |
| 100 | + (target (quil:qubit-index (second (quil:application-arguments instr)))) |
| 101 | + (Xc (aref (error-qvm-X-vector qvm) control)) |
| 102 | + (Xt (aref (error-qvm-X-vector qvm) target)) |
| 103 | + (Zc (aref (error-qvm-Z-vector qvm) control)) |
| 104 | + (Zt (aref (error-qvm-Z-vector qvm) target))) |
| 105 | + (when (plusp Xc) |
| 106 | + (setf (aref (error-qvm-X-vector qvm) target) |
| 107 | + (logxor Xt #b1))) |
| 108 | + (when (plusp Zt) |
| 109 | + (setf (aref (error-qvm-Z-vector qvm) control) |
| 110 | + (logxor Zc #b1))))) |
| 111 | + (t |
| 112 | + (error "Gate ~a is not CNOT-dihedral." instr)))) |
| 113 | + (incf (qvm::pc qvm)) |
| 114 | + qvm) |
| 115 | + |
| 116 | +;;;;;;;;;;;;;;;;;;;;;;;;; FOWLER-QVM Methods ;;;;;;;;;;;;;;;;;;;;;;;;; |
| 117 | + |
| 118 | +(defmethod copy-fowler-qvm ((qvm error-qvm)) |
| 119 | + (let ((new-qvm |
| 120 | + (make-instance 'error-qvm |
| 121 | + :noise-class (fowler-qvm-noise-class qvm) |
| 122 | + :noise-probability (fowler-qvm-noise-probability qvm) |
| 123 | + :num-qubits (error-qvm-num-qubits qvm) |
| 124 | + :gate-definitions (qvm::gate-definitions qvm) |
| 125 | + :wait-function (qvm::wait-function qvm) |
| 126 | + :classical-memory-subsystem (qvm::classical-memory-subsystem qvm)))) |
| 127 | + (setf (error-qvm-X-vector new-qvm) (copy-seq (error-qvm-X-vector qvm)) |
| 128 | + (error-qvm-Z-vector new-qvm) (copy-seq (error-qvm-Z-vector qvm))) |
| 129 | + new-qvm)) |
| 130 | + |
| 131 | +(defmethod %fast-apply ((qvm error-qvm) instr-name qubit) |
| 132 | + (cond |
| 133 | + ((string= "X" instr-name) |
| 134 | + (setf (aref (error-qvm-X-vector qvm) qubit) |
| 135 | + (logxor #b1 (aref (error-qvm-X-vector qvm) qubit)))) |
| 136 | + ((string= "Z" instr-name) |
| 137 | + (setf (aref (error-qvm-Z-vector qvm) qubit) |
| 138 | + (logxor #b1 (aref (error-qvm-Z-vector qvm) qubit)))) |
| 139 | + ((string= "Y" instr-name) |
| 140 | + (setf (aref (error-qvm-X-vector qvm) qubit) |
| 141 | + (logxor #b1 (aref (error-qvm-X-vector qvm) qubit)) |
| 142 | + (aref (error-qvm-Z-vector qvm) qubit) |
| 143 | + (logxor #b1 (aref (error-qvm-Z-vector qvm) qubit)))) |
| 144 | + (t |
| 145 | + (error "Bad instruction in %FAST-APPLY: ~a" instr-name)))) |
0 commit comments