2024-12-08 22:06:58 -08:00
|
|
|
;;;; Functions for creating and applying quantum gates
|
2024-12-07 21:24:22 -08:00
|
|
|
(in-package :cl-quantum/state)
|
2024-12-06 07:54:58 -08:00
|
|
|
|
2024-12-08 22:06:58 -08:00
|
|
|
;; Fix SBCL's strict handling of `defconstant'
|
2024-12-08 09:41:05 -08:00
|
|
|
(defmacro define-constant (name value &optional doc)
|
|
|
|
"Define NAME to be a constant with value VALUE. If NAME is already defined, do
|
|
|
|
nothing."
|
|
|
|
`(defconstant ,name (if (boundp ',name)
|
|
|
|
(symbol-value ',name)
|
|
|
|
,value)
|
|
|
|
,@(when doc (list doc))))
|
|
|
|
|
|
|
|
;;; Gates and Operators:
|
|
|
|
(define-constant +unset-projector+
|
|
|
|
#2A((1 0)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 0))
|
|
|
|
"|0><0| projector matrix.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +set-projector+
|
|
|
|
#2A((0 0)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 1))
|
|
|
|
"|1><1| projector matrix.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +identity-2x2+
|
2024-12-08 22:06:58 -08:00
|
|
|
(make-identity-matrix 2)
|
|
|
|
"A 2 by 2 identity matrix.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +pauli-x-gate+
|
|
|
|
#2A((0 1)
|
2024-12-08 22:06:58 -08:00
|
|
|
(1 0))
|
|
|
|
"A 2 by 2 Pauli X gate that can be applied to a single qbit.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +pauli-y-gate+
|
|
|
|
#2A((0 #C(0 -1))
|
2024-12-08 22:06:58 -08:00
|
|
|
(#C(0 -1) 0))
|
|
|
|
"A 2 by 2 Pauli Y gate that can be applied to a single qbit.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +pauli-z-gate+
|
|
|
|
#2A((1 0)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 -1))
|
|
|
|
"A 2 by 2 Pauli Z gate that can be applied to a single qbit.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +hadamard-gate+
|
|
|
|
(let ((oort (/ (sqrt 2))))
|
|
|
|
(make-array '(2 2) :initial-contents
|
|
|
|
`((,oort ,oort)
|
2024-12-08 22:06:58 -08:00
|
|
|
(,oort ,(- oort)))))
|
|
|
|
"A 2 by 2 Hadamard gate that can be applied to a single qbit.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +phase-gate+
|
|
|
|
#2A((1 0)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 #C(0 1)))
|
|
|
|
"A 2 by 2 phase gate that can be applied to a single qbit.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +pi/8-gate+
|
|
|
|
(make-array '(2 2) :initial-contents
|
|
|
|
`((1 0)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 ,(exp (complex 0 (/ pi 4))))))
|
|
|
|
"A 2 by 2 phase gate that can be applied to a single qbit.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +cnot-gate+
|
|
|
|
#2A((1 0 0 0)
|
|
|
|
(0 1 0 0)
|
|
|
|
(0 0 0 1)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 0 1 0))
|
|
|
|
"A 4 by 4 controlled NOT (Pauli X) gate that applies to a 2 qbit state. The 0
|
|
|
|
indexed qbit is the target and the 1 indexed qbit is the control.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +cz-gate+
|
|
|
|
#2A((1 0 0 0)
|
|
|
|
(0 1 0 0)
|
|
|
|
(0 0 1 0)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 0 0 -1))
|
|
|
|
"A 4 by 4 controlled Pauli Z gate that applies to a 2 qbit state.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +swap-gate+
|
|
|
|
#2A((1 0 0 0)
|
|
|
|
(0 0 1 0)
|
|
|
|
(0 1 0 0)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 0 0 1))
|
|
|
|
"A 4 by 4 swap gate that applies to a 2 qbit state.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
(define-constant +ccnot-gate+
|
|
|
|
#2A((1 0 0 0 0 0 0 0)
|
|
|
|
(0 1 0 0 0 0 0 0)
|
|
|
|
(0 0 1 0 0 0 0 0)
|
|
|
|
(0 0 0 1 0 0 0 0)
|
|
|
|
(0 0 0 0 1 0 0 0)
|
|
|
|
(0 0 0 0 0 1 0 0)
|
|
|
|
(0 0 0 0 0 0 0 1)
|
2024-12-08 22:06:58 -08:00
|
|
|
(0 0 0 0 0 0 1 0))
|
|
|
|
"An 8 by 8 2-controlled NOT (Pauli X) gate that applies to a 3 qbit sate. The
|
|
|
|
0 indexed qbit is the target and the 1 and 2 indexed qbits are the controls.")
|
2024-12-08 09:41:05 -08:00
|
|
|
|
|
|
|
;;; State Functions:
|
2024-12-06 07:54:58 -08:00
|
|
|
(defun normal-state-p (state &key (places 5))
|
|
|
|
"Return non-nil if state is normalized. PLACES is the number of places to
|
|
|
|
round the norm of STATE before checking."
|
|
|
|
(= (round-to-place (dot state state) places) 1))
|
|
|
|
|
|
|
|
(defun normalize-state (state)
|
|
|
|
"Return a copy of STATE that is normalized."
|
|
|
|
(/vs state (norm state)))
|
|
|
|
|
2024-12-07 21:24:22 -08:00
|
|
|
(defun nnormalize-state (state)
|
|
|
|
"Normalize STATE by mutating it."
|
|
|
|
(let ((norm (norm state)))
|
|
|
|
(dotimes (i (length state) state)
|
|
|
|
(setf (aref state i) (/ (aref state i) norm)))))
|
|
|
|
|
|
|
|
(defun state-bits (state)
|
|
|
|
"Return the number of bits in STATE."
|
|
|
|
(values (ceiling (log (length state) 2))))
|
|
|
|
|
2024-12-08 22:06:58 -08:00
|
|
|
(defun make-zero-state (bits)
|
|
|
|
"Make a normalized state with a value of zero (probability of 1 in the zero
|
|
|
|
place)."
|
|
|
|
(let ((arr (make-array (ash 1 bits) :initial-element 0)))
|
|
|
|
(setf (aref arr 0) 1)
|
|
|
|
arr))
|
|
|
|
|
2024-12-07 21:24:22 -08:00
|
|
|
(defun make-normal-state (probabilities)
|
|
|
|
"Create a new normalized state with the probability of each state
|
|
|
|
corresponding to an element in PROBABILITIES."
|
|
|
|
(map 'vector 'sqrt probabilities))
|
|
|
|
|
2024-12-06 07:54:58 -08:00
|
|
|
(defun make-uniform-normal-state (bits)
|
|
|
|
"Make a uniform normalized quantum state of BITS qbits."
|
|
|
|
(let ((size (ash 1 bits)))
|
|
|
|
(make-array (ash 1 bits) :initial-element (/ (sqrt size)))))
|
2024-12-06 22:24:29 -08:00
|
|
|
|
|
|
|
(defun bit-unset-index (bit n &key (period (ash 1 bit)))
|
|
|
|
"Return the Nth index in a state in which BIT is 0."
|
|
|
|
(multiple-value-bind (quo rem)
|
|
|
|
(floor n period)
|
|
|
|
(+ (* 2 period quo) rem)))
|
|
|
|
|
|
|
|
(defun bit-set-index (bit n &key (period (ash 1 bit)))
|
|
|
|
"Return the Nth index in a state in which BIT is 1."
|
2024-12-07 21:24:22 -08:00
|
|
|
(+ period (bit-unset-index bit n :period period)))
|
2024-12-06 22:24:29 -08:00
|
|
|
|
2024-12-08 22:06:58 -08:00
|
|
|
(defun bit-set-p (bit n)
|
|
|
|
"Return non-nil if BIT would be set at index N."
|
|
|
|
(let ((period (ash 1 bit)))
|
|
|
|
(>= (rem n (* 2 period)) period)))
|
|
|
|
|
2024-12-06 22:24:29 -08:00
|
|
|
(defun bit-probability (state bit)
|
|
|
|
"Return the probability that BIT is set in STATE."
|
|
|
|
(setq state (normalize-state state))
|
|
|
|
(loop with period = (ash 1 bit)
|
|
|
|
for i below (/ (length state) 2)
|
|
|
|
for index = (bit-set-index bit i :period period)
|
|
|
|
for coef = (aref state index)
|
|
|
|
summing (* coef coef)))
|
|
|
|
|
2024-12-07 21:24:22 -08:00
|
|
|
(defun nmeasure (state bit &key (places 5))
|
|
|
|
"Collapse BIT in STATE by measuring it. This will return t or nil depending on
|
|
|
|
the state the bit collapsed to. Note that this will also modify STATE. The
|
|
|
|
probability will be rounded to PLACES before calculations are carried out."
|
|
|
|
(loop with prob = (round-to-place (bit-probability state bit) places)
|
|
|
|
;; Theocratically there are multiple numbers that could be equivalent
|
|
|
|
;; to 100% here, but the chance of those failing is so low anyway that
|
|
|
|
;; it doesn't matter.
|
2024-12-06 22:24:29 -08:00
|
|
|
with limit = (* most-positive-fixnum prob)
|
|
|
|
with rnum = (random most-positive-fixnum)
|
2024-12-07 21:24:22 -08:00
|
|
|
with result = (< rnum limit)
|
2024-12-06 22:24:29 -08:00
|
|
|
with period = (ash 1 bit)
|
2024-12-07 21:24:22 -08:00
|
|
|
with 1-prob = (- 1 prob)
|
2024-12-06 22:24:29 -08:00
|
|
|
for i below (/ (length state) 2)
|
|
|
|
for unset-index = (bit-unset-index bit i :period period)
|
|
|
|
for set-index = (+ period unset-index)
|
|
|
|
for unset-coef = (aref state unset-index)
|
|
|
|
for set-coef = (aref state set-index)
|
|
|
|
if result
|
|
|
|
do (setf (aref state unset-index) 0
|
2024-12-07 21:24:22 -08:00
|
|
|
(aref state set-index)
|
|
|
|
(sqrt (/ (* set-coef set-coef) prob)))
|
2024-12-06 22:24:29 -08:00
|
|
|
else
|
2024-12-07 21:24:22 -08:00
|
|
|
do (setf (aref state unset-index)
|
|
|
|
(sqrt (/ (* unset-coef unset-coef) 1-prob))
|
2024-12-06 22:24:29 -08:00
|
|
|
(aref state set-index) 0)
|
|
|
|
finally (return (values result state))))
|
|
|
|
|
2024-12-07 21:24:22 -08:00
|
|
|
(defun measure (state bit &key (places 5))
|
|
|
|
"Like `nmeasure', but don't modify STATE. Note that the new state is returned
|
|
|
|
as the second value, with the first value being the result of the
|
|
|
|
measurement. You will probably want to save the second value as the first value
|
|
|
|
too as the second value alone means pretty much nothing."
|
|
|
|
(nmeasure (copy-seq state) bit :places places))
|
|
|
|
|
2024-12-08 09:41:05 -08:00
|
|
|
(defun ncollapse (state &key (places 5))
|
|
|
|
"Collapse STATE into a single quantum state. After this call, STATE will be a
|
|
|
|
state with a zero coefficient in all but one place. This returns two values, the
|
|
|
|
first is the index into which STATE collapsed and the second is STATE."
|
|
|
|
(nnormalize-state state)
|
|
|
|
(loop with rval = (random most-positive-fixnum)
|
|
|
|
with did-find = nil
|
|
|
|
for i below (length state)
|
|
|
|
for coef = (aref state i)
|
|
|
|
for plimit = 0 then limit
|
|
|
|
for prob = (round-to-place (* coef coef) places)
|
|
|
|
for limit = (+ plimit (* prob (1- most-positive-fixnum)))
|
|
|
|
when (and (not did-find) (< rval limit))
|
|
|
|
do (setf (aref state i) 1
|
|
|
|
did-find i)
|
|
|
|
else
|
|
|
|
do (setf (aref state i) 0)
|
|
|
|
finally (return (values did-find state))))
|
|
|
|
|
|
|
|
(defun collapse (state &key (places 5))
|
|
|
|
"Collapse STATE into a single quantum state. This is like `ncollapse', except
|
|
|
|
that it does not modify STATE. Thus, you will probably want to keep both
|
|
|
|
returned values."
|
|
|
|
(ncollapse (copy-seq state) :places places))
|
|
|
|
|
2024-12-06 22:24:29 -08:00
|
|
|
(defun make-operator (bits operator target)
|
|
|
|
"Create an operator matrix that can act on a state with BITS bits and will
|
|
|
|
apply OPERATOR to TARGET."
|
|
|
|
(loop with out = (if (= (1- bits) target)
|
|
|
|
operator
|
2024-12-08 09:41:05 -08:00
|
|
|
+identity-2x2+)
|
2024-12-06 22:24:29 -08:00
|
|
|
for i from (- bits 2) downto 0
|
|
|
|
do (setq out (tensor-mm out (if (= i target)
|
|
|
|
operator
|
2024-12-08 09:41:05 -08:00
|
|
|
+identity-2x2+)))
|
2024-12-06 22:24:29 -08:00
|
|
|
finally (return out)))
|
|
|
|
|
2024-12-07 21:24:22 -08:00
|
|
|
(defun make-controlled-operator (bits operator target control)
|
2024-12-06 22:24:29 -08:00
|
|
|
"Create an operator matrix that can act on a state with BITS bits and will
|
2024-12-07 21:24:22 -08:00
|
|
|
apply OPERATOR to TARGET if CONTROL is set."
|
2024-12-06 22:24:29 -08:00
|
|
|
(labels ((matrix-for (bit target-operator control-operator)
|
|
|
|
(cond
|
|
|
|
((= bit target) target-operator)
|
2024-12-07 21:24:22 -08:00
|
|
|
((= bit control) control-operator)
|
2024-12-08 09:41:05 -08:00
|
|
|
(t +identity-2x2+)))
|
2024-12-06 22:24:29 -08:00
|
|
|
(tensor-chain (target-operator control-operator)
|
|
|
|
(loop with out = (matrix-for (1- bits) target-operator
|
|
|
|
control-operator)
|
|
|
|
for i from (- bits 2) downto 0
|
|
|
|
do (setq out (tensor-mm out (matrix-for i target-operator
|
|
|
|
control-operator)))
|
|
|
|
finally (return out))))
|
2024-12-08 09:41:05 -08:00
|
|
|
(+mm (tensor-chain +identity-2x2+ +unset-projector+)
|
|
|
|
(tensor-chain operator +set-projector+))))
|
2024-12-06 22:24:29 -08:00
|
|
|
|
2024-12-08 22:06:58 -08:00
|
|
|
(defun make-n-toffoli-operator (bits target controls)
|
|
|
|
"Create an n-Toffoli gate for a state of BITS bits that targets TARGET and is
|
|
|
|
controlled by CONTROLS."
|
|
|
|
(assert (not (member target controls :test '=))
|
|
|
|
(target controls)
|
|
|
|
"Target ~s cannot be in control set ~s" target controls)
|
|
|
|
(let* ((state-size (ash 1 bits))
|
|
|
|
(mat (make-identity-matrix state-size))
|
|
|
|
(offset (ash 1 target)))
|
|
|
|
(loop for i below (/ state-size 2)
|
|
|
|
for index = (bit-unset-index target i)
|
|
|
|
when (every (lambda (elt)
|
|
|
|
(bit-set-p elt index))
|
|
|
|
controls)
|
|
|
|
do (nswap-rows mat index (+ index offset)))
|
|
|
|
mat))
|
|
|
|
|
|
|
|
(defun make-n-controlled-z-operator (bits target controls)
|
|
|
|
"Create an n-controlled z gate for a state of BITS bits that targets TARGET
|
|
|
|
and is controlled by CONTROLS."
|
|
|
|
(assert (not (member target controls :test '=))
|
|
|
|
(target controls)
|
|
|
|
"Target ~s cannot be in control set ~s" target controls)
|
|
|
|
(let* ((state-size (ash 1 bits))
|
|
|
|
(mat (make-identity-matrix state-size)))
|
|
|
|
(loop for i below (/ state-size 2)
|
|
|
|
for index = (bit-set-index target i)
|
|
|
|
when (every (lambda (elt)
|
|
|
|
(bit-set-p elt index))
|
|
|
|
controls)
|
|
|
|
do (setf (aref mat index index) -1))
|
|
|
|
mat))
|
|
|
|
|
2024-12-07 21:24:22 -08:00
|
|
|
(defun replace-state (target template)
|
|
|
|
"Replace each element of TARGET with the corresponding element in TEMPLATE."
|
|
|
|
(assert (= (length target) (length template))
|
|
|
|
(target template)
|
|
|
|
"Vectors must be of the same length: ~s and ~s" target template)
|
|
|
|
(dotimes (i (length target) target)
|
|
|
|
(setf (aref target i) (aref template i))))
|
|
|
|
|
2024-12-08 22:06:58 -08:00
|
|
|
(defun apply-gate (state operator target)
|
2024-12-07 21:24:22 -08:00
|
|
|
"Apply OPERATOR to the bit numbered TARGET in STATE."
|
|
|
|
(*mv (make-operator (state-bits state) operator target) state))
|
|
|
|
|
2024-12-08 22:06:58 -08:00
|
|
|
(defun napply-gate (state operator target)
|
2024-12-07 21:24:22 -08:00
|
|
|
"Apply OPERATOR to the bit numbered TARGET in STATE. This modifies state."
|
2024-12-08 22:06:58 -08:00
|
|
|
(replace-state state (apply-gate state operator target)))
|
2024-12-07 21:24:22 -08:00
|
|
|
|
2024-12-08 22:06:58 -08:00
|
|
|
(defun apply-controlled-gate (state operator target control)
|
2024-12-07 21:24:22 -08:00
|
|
|
"Apply OPERATOR to the bit numbered TARGET in STATE if CONTROL is set."
|
|
|
|
(*mv (make-controlled-operator (state-bits state) operator target control)
|
|
|
|
state))
|
|
|
|
|
2024-12-08 22:06:58 -08:00
|
|
|
(defun napply-controlled-gate (state operator target control)
|
2024-12-07 21:24:22 -08:00
|
|
|
"Apply OPERATOR to the bit numbered TARGET in STATE if CONTROL is set. This
|
|
|
|
modified STATE."
|
2024-12-08 22:06:58 -08:00
|
|
|
(replace-state state (apply-controlled-gate state operator target control)))
|