Add examples and clean up some stuff

This commit is contained in:
Alexander Rosenberg 2024-12-08 22:06:58 -08:00
parent 5adc755be4
commit 9b8584bd6f
Signed by: Zander671
GPG Key ID: 5FD0394ADBD72730
10 changed files with 275 additions and 102 deletions

View File

@ -1,9 +1,16 @@
;;;; High-level interface for building quantum circuits
(in-package :cl-quantum/circuit) (in-package :cl-quantum/circuit)
(defparameter *circuit-measure-places* 5 (defparameter *circuit-measure-places* 5
"The number of places to use with the :measure instruction in circuits.") "The number of places to use with the :measure instruction in circuits.")
(defun circuit-matrix-operation (state operator &rest args) (defun circuit-arbitrary-gate (state operator gate target &optional control)
(declare (ignorable operator))
(if control
(napply-controlled-gate state gate target control)
(napply-gate state gate target)))
(defun circuit-matrix-operation (state operator target &optional control)
(let ((matrix (case operator (let ((matrix (case operator
(:* +identity-2x2+) (:* +identity-2x2+)
(:x +pauli-x-gate+) (:x +pauli-x-gate+)
@ -14,112 +21,114 @@
(:t +pi/8-gate+) (:t +pi/8-gate+)
(:cnot +pauli-x-gate+) (:cnot +pauli-x-gate+)
(:cz +pauli-z-gate+)))) (:cz +pauli-z-gate+))))
(destructuring-bind (target &optional control) args (if control
(if control (napply-controlled-gate state matrix target control)
(napply-controlled-operator state matrix target control) (napply-gate state matrix target))))
(napply-operator state matrix target)))))
(defun circuit-n-controlled-gate (state operator target controls)
(let ((func (case operator
(:ntoff 'make-n-toffoli-operator)
(:ncz 'make-n-controlled-z-operator))))
(replace-state state (*mv (funcall func (state-bits state)
target controls)
state))))
(defparameter *circuit-operators* (defparameter *circuit-operators*
;; Operator, # args, has output?, function ;; Operator, # args, more args?, has output?, function
;; The output is always the last argument ;; The output is always the last argument
`((:* 1 nil circuit-matrix-operation) `((:gate 2 nil nil circuit-arbitrary-gate)
(:x 1 nil circuit-matrix-operation) (:cgate 3 nil nil circuit-arbitrary-gate)
(:y 1 nil circuit-matrix-operation) (:* 1 nil nil circuit-matrix-operation)
(:z 1 nil circuit-matrix-operation) (:x 1 nil nil circuit-matrix-operation)
(:h 1 nil circuit-matrix-operation) (:y 1 nil nil circuit-matrix-operation)
(:p 1 nil circuit-matrix-operation) (:z 1 nil nil circuit-matrix-operation)
(:t 1 nil circuit-matrix-operation) (:h 1 nil nil circuit-matrix-operation)
(:cnot 2 nil circuit-matrix-operation) (:p 1 nil nil circuit-matrix-operation)
(:cz 2 nil circuit-matrix-operation) (:t 1 nil nil circuit-matrix-operation)
(:measure 2 t ,(lambda (state operator &rest args) (:cnot 2 nil nil circuit-matrix-operation)
(declare (ignorable operator)) (:cz 2 nil nil circuit-matrix-operation)
(nmeasure state (car args) (:measure 2 nil t ,(lambda (state operator &rest args)
:places *circuit-measure-places*))))) (declare (ignorable operator))
(nmeasure state (car args)
:places *circuit-measure-places*)))
(:ntoff 2 nil nil circuit-n-controlled-gate)
(:ncz 2 nil nil circuit-n-controlled-gate)))
(defun make-circuit () (defun make-circuit ()
"Create a new blank circuit." "Create a new blank circuit."
'(0)) '(:circuit))
(defun add-to-circuit (circuit operator &rest args) (defun add-to-circuit (circuit operator &rest args)
"Add OPERATOR to CIRCUIT." "Add OPERATOR to CIRCUIT."
(let ((entry (assoc operator *circuit-operators*)) (let ((entry (assoc operator *circuit-operators*)))
(largest-arg (apply 'max (remove-if-not 'integerp args))))
(unless entry (unless entry
(error "Unknown circuit operator: ~s" operator)) (error "Unknown circuit operator: ~s" operator))
(destructuring-bind (name arg-count &rest r) entry (destructuring-bind (name arg-count has-rest &rest r) entry
(declare (ignorable name r)) (declare (ignorable name r))
(unless (= arg-count (length args)) (unless (or (and has-rest (>= (length args) arg-count))
(error "Operator ~s expects ~s args, got ~s" operator (= (length args) arg-count))
arg-count (length args))) (error "Operator ~s expects ~@[~*exactly ~]~s arg~:p, got ~s" operator
(when (> (1+ largest-arg) (car circuit)) (not has-rest) arg-count (length args)))
(setf (car circuit) (1+ largest-arg)))
(nconc circuit (list (cons operator args)))) (nconc circuit (list (cons operator args))))
circuit)) circuit))
(defmacro with-build-circuit (&body body) (defmacro with-build-circuit (&body body)
"Create a circuit using a simple DSL. BODY can be any valid Lisp forms, in "Create a circuit using a simple DSL. BODY can be any valid Lisp forms, in
addition to function calls to functions named in `*circuit-operators*'." addition to function calls to functions named in `*circuit-operators*'."
(let ((circuit-var (gensym)) (let ((circuit-var (gensym)))
(size-var (gensym)) `(let ((,circuit-var))
(ao-func (gensym)) (macrolet
(ao-entry-var (gensym)) (,@(mapcar (lambda (oper)
(ao-i-var (gensym))) (let ((arg (gensym))
`(let ((,circuit-var) (arg-list (loop repeat (second oper)
(,size-var 0)) collect (gensym)))
(flet ((,ao-func (,ao-entry-var) (whole-arg (when (third oper)
(dolist (,ao-i-var ,ao-entry-var) (gensym))))
(when (and (integerp ,ao-i-var) `(,(car oper) (&whole ,arg
(< ,size-var ,ao-i-var)) ,@arg-list
(setq ,size-var ,ao-i-var))) ,@(when (third oper)
(push ,ao-entry-var ,circuit-var))) (list '&rest whole-arg)))
(macrolet (declare (ignorable ,@arg-list
(,@(mapcar (lambda (oper) ,@(when (third oper)
(let ((arg (gensym))) (list whole-arg))))
`(,(car oper) (&rest ,arg) `(push (list ,@,arg) ,',circuit-var))))
(assert (= (length ,arg) ,(second oper)) *circuit-operators*))
() ,@body)
"~s expects ~s arguments, got ~s" (cons :circuit (nreverse ,circuit-var)))))
,(car oper) ,(second oper) (length ,arg))
`(,',ao-func (list ,',(car oper) ,@,arg)))))
*circuit-operators*))
,@body))
(cons (1+ ,size-var) (nreverse ,circuit-var)))))
(defun apply-circuit-operator-to-state (state operator args) (defun apply-circuit-operator-to-state (state operator args)
"Apply the circuit operator OPERATOR to STATE by calling its function with "Apply the circuit operator OPERATOR to STATE by calling its function with
ARGS." ARGS."
(destructuring-bind (&optional name arg-count has-output function) (destructuring-bind (&optional name arg-count has-rest has-output function)
(assoc operator *circuit-operators*) (assoc operator *circuit-operators*)
(declare (ignorable name arg-count)) (declare (ignorable name arg-count has-rest))
(assert function () (assert function ()
"Invalid circuit operator: ~s" operator) "Invalid circuit operator: ~s" operator)
(let ((output (apply function state operator args))) (let ((output (apply function state operator args)))
(when has-output (when has-output
(cons (car (last args)) output))))) (cons (car (last args)) output)))))
(defun run-circuit (circuit &key bits coefficients probabilities (places 5)) (defun run-circuit (circuit &key bits uniform coefficients probabilities (places 5))
"Run the circuit CIRCUIT and return the final state. The initial state can be "Run the circuit CIRCUIT and return the final state. The initial state can be
specified in one of three ways: specified in one of three ways:
- BITS: the number of qbits - BITS: the number of qbits
- COEFFICIENTS: the initial coefficients - COEFFICIENTS: the initial coefficients
- PROBABILITES: the initial probabilities" - PROBABILITES: the initial probabilities"
(assert (= 1 (count-if 'identity (list bits coefficients probabilities))) (assert (= 1 (count-if 'identity (list bits coefficients probabilities uniform)))
() ()
"Exactly one of BITS, COEFFICIENTS, and PROBABILITIES can be present") "Exactly one of BITS, UNIFORM, COEFFICIENTS, and PROBABILITIES can ~
be present")
(let ((state (cond (let ((state (cond
(bits (make-uniform-normal-state bits)) (bits (make-zero-state bits))
(uniform (make-uniform-normal-state uniform))
(coefficients (coerce coefficients 'vector)) (coefficients (coerce coefficients 'vector))
(probabilities (make-normal-state probabilities))))) (probabilities (make-normal-state probabilities)))))
(destructuring-bind (circuit-size &rest elements) circuit (values
(when (> circuit-size (state-bits state)) state
(error "Circuit needs at least ~s bits, got ~s" circuit-size (loop with *circuit-measure-places* = places
(state-bits state))) for element in (cdr circuit)
(values for name = (car element)
state for args = (cdr element)
(loop with *circuit-measure-places* = places for result = (apply-circuit-operator-to-state state name args)
for element in elements when result
for name = (car element) collect result))))
for args = (cdr element)
for result = (apply-circuit-operator-to-state state name args)
when result
collect result)))))

View File

@ -2,6 +2,8 @@
:version "0.0.1" :version "0.0.1"
:description "Quantum computing operations in pure Common Lisp." :description "Quantum computing operations in pure Common Lisp."
:author "Alexander Rosenberg <zanderpkg@pm.me>" :author "Alexander Rosenberg <zanderpkg@pm.me>"
:maintainer "Alexander Rosenberg <zanderpkg@pm.me>"
:homepage "https://git.zander.im/Zander671/cl-quantum"
:license "GPL3" :license "GPL3"
:depends-on () :depends-on ()
:serial t :serial t
@ -10,11 +12,22 @@
(:file "math") (:file "math")
(:file "state") (:file "state")
(:file "circuit") (:file "circuit")
(:file "pprint"))) (:file "pprint"))
:long-description
#.(uiop:read-file-string
(uiop:subpathname *load-pathname* "README.md")))
(defsystem #:cl-quantum/parse (defsystem #:cl-quantum/parse
:description "Textual state parsing component for cl-quantum." :description "Textual state parsing component for cl-quantum."
:depends-on (#:cl-ppcre) :depends-on (#:cl-quantum #:cl-ppcre)
:serial t
:components :components
((:file "parse"))) ((:file "parse")))
(defsystem #:cl-quantum/examples
:description "A collection of examples for ql-quantum."
:depends-on (#:cl-quantum)
:serial t
:components
((:file "examples/package")
(:file "examples/grover")
(:file "examples/bell")))

30
examples/bell.lisp Normal file
View File

@ -0,0 +1,30 @@
;;;; Example Bell state creation circuits
(in-package :cl-quantum/examples)
(defun make-bell-phi+-circuit ()
"Return a circuit that makes a Bell phi+ state. That is |00>+|11>."
(with-build-circuit
(:h 0)
(:cnot 1 0)))
(defun make-bell-phi--circuit ()
"Return a circuit that makes a Bell phi- state. That is |00>-|11>."
(with-build-circuit
(:h 0)
(:cnot 1 0)
(:z 1)))
(defun make-bell-psi+-circuit ()
"Return a circuit that makes a Bell psi+ state. That is |01>+|10>."
(with-build-circuit
(:x 1)
(:h 0)
(:cnot 1 0)))
(defun make-bell-psi--circuit ()
"Return a circuit that makes a Bell psi- state. That is |01>-|10>."
(with-build-circuit
(:x 1)
(:h 0)
(:cnot 1 0)
(:z 1)))

38
examples/grover.lisp Normal file
View File

@ -0,0 +1,38 @@
;;;; An example of Grover's algorithm (quantum search)
(in-package :cl-quantum/examples)
(defun count-grover-iterations (bits targets)
"Count the number of iterations it takes to have a high probability of finding
TARGETS in a search space of 2^BITS."
(values (floor (* (/ pi 4) (sqrt (/ (ash 1 bits) targets))))))
(defun make-grover-circuit (bits target)
"Generate a quantum circuit that runs Grover's algorithm over a state of BITS
bits and finds when the state is equal to TARGET."
(assert (> (ash 1 bits) target)
(bits target)
"Target bit of ~s out of range for state with ~s bits." target bits)
(with-build-circuit
;; Setup
(loop for i below bits do (:h i))
;; Oracle
(loop
repeat (count-grover-iterations bits 1)
do
(loop for i below bits
for cur = (logand (ash target (- i)) 1)
when (zerop cur)
do (:x i))
(:ncz 0 (loop for i from 1 below bits collect i))
(loop for i below bits
for cur = (logand (ash target (- i)) 1)
when (zerop cur)
do (:x i))
;; Diffuser
(loop for i below bits do (:h i))
(loop for i below bits do (:x i))
(:ncz 0 (loop for i from 1 below bits collect i))
(loop for i below bits do (:x i))
(loop for i below bits do (:h i)))))

8
examples/package.lisp Normal file
View File

@ -0,0 +1,8 @@
(defpackage :cl-quantum/examples
(:documentation "A collection of examples for ql-quantum.")
(:use :cl :cl-quantum/state :cl-quantum/circuit)
(:export #:make-grover-circuit
#:make-bell-phi+-circuit
#:make-bell-phi--circuit
#:make-bell-psi+-circuit
#:make-bell-psi--circuit))

View File

@ -1,3 +1,4 @@
;;;; Basic linear algebra subroutines used to implement the quantum operators
(in-package :cl-quantum/math) (in-package :cl-quantum/math)
(defmacro domatrix ((var matrix &optional retval) &body body) (defmacro domatrix ((var matrix &optional retval) &body body)

View File

@ -1,4 +1,6 @@
(defpackage :cl-quantum/math (defpackage :cl-quantum/math
(:documentation "Basic linear algebra subroutines used to implement the
quantum operators.")
(:use :cl) (:use :cl)
(:export #:domatrix (:export #:domatrix
#:mapmatrix #:mapmatrix
@ -47,8 +49,10 @@
#:vector=)) #:vector=))
(defpackage :cl-quantum/state (defpackage :cl-quantum/state
(:documentation "Functions for creating and applying quantum gates.")
(:use :cl :cl-quantum/math) (:use :cl :cl-quantum/math)
(:export #:+unset-projector+ (:export #:define-constant
#:+unset-projector+
#:+set-projector+ #:+set-projector+
#:+identity-2x2+ #:+identity-2x2+
#:+pauli-x-gate+ #:+pauli-x-gate+
@ -65,6 +69,7 @@
#:normalize-state #:normalize-state
#:nnormalize-state #:nnormalize-state
#:state-bits #:state-bits
#:make-zero-state
#:make-normal-state #:make-normal-state
#:make-uniform-normal-state #:make-uniform-normal-state
#:bit-unset-index #:bit-unset-index
@ -76,12 +81,16 @@
#:collapse #:collapse
#:make-operator #:make-operator
#:make-controlled-operator #:make-controlled-operator
#:apply-operator #:make-n-toffoli-operator
#:napply-operator #:make-n-controlled-z-operator
#:apply-controlled-operator #:replace-state
#:napply-controlled-operator)) #:apply-gate
#:napply-gate
#:apply-controlled-gate
#:napply-controlled-gate))
(defpackage :cl-quantum/circuit (defpackage :cl-quantum/circuit
(:documentation "High-level interface for building quantum circuits.")
(:use :cl :cl-quantum/math :cl-quantum/state) (:use :cl :cl-quantum/math :cl-quantum/state)
(:export #:*circuit-measure-places* (:export #:*circuit-measure-places*
#:*circuit-operators* #:*circuit-operators*
@ -91,6 +100,7 @@
#:run-circuit)) #:run-circuit))
(defpackage :cl-quantum/pprint (defpackage :cl-quantum/pprint
(:documentation "High-level interface for building quantum circuits.")
(:use :cl :cl-quantum/math :cl-quantum/state) (:use :cl :cl-quantum/math :cl-quantum/state)
(:export #:pprint-complex (:export #:pprint-complex
#:pprint-format-bits #:pprint-format-bits

View File

@ -1,5 +1,7 @@
;;;; Parse back the states printed by pprint.lisp
(defpackage :cl-quantum/parse (defpackage :cl-quantum/parse
(:use :cl :cl-quantum/state) (:documentation "Parse back the states printed by pprint.lisp.")
(:use :cl :cl-quantum/math :cl-quantum/state)
(:export #:parse-real (:export #:parse-real
#:parse-complex #:parse-complex
#:parse-state #:parse-state
@ -44,7 +46,7 @@ stopped. That is, the index of the first un-parsed character."
(list 0 0) (list 0 0)
(error "Malformed number: ~s" (subseq string start end)))))) (error "Malformed number: ~s" (subseq string start end))))))
(define-constatnt +parse-complex-regexp+ (define-constant +parse-complex-regexp+
(ppcre:create-scanner (ppcre:create-scanner
"^\\s*([-+])?\\s*([-+]?)([0-9/.]+(?:[eE][-+]?[0-9]+)?)?(i)?" "^\\s*([-+])?\\s*([-+]?)([0-9/.]+(?:[eE][-+]?[0-9]+)?)?(i)?"
:extended-mode t) :extended-mode t)

View File

@ -1,3 +1,4 @@
;;;; Create nice looking textual representations of quantum states
(in-package :cl-quantum/pprint) (in-package :cl-quantum/pprint)
(defun pprint-complex (n &key parens (places 5)) (defun pprint-complex (n &key parens (places 5))

View File

@ -1,6 +1,7 @@
;;;; Functions for creating and applying quantum gates
(in-package :cl-quantum/state) (in-package :cl-quantum/state)
;;; Fix SBCL's strict handling of `defconstant' ;; Fix SBCL's strict handling of `defconstant'
(defmacro define-constant (name value &optional doc) (defmacro define-constant (name value &optional doc)
"Define NAME to be a constant with value VALUE. If NAME is already defined, do "Define NAME to be a constant with value VALUE. If NAME is already defined, do
nothing." nothing."
@ -12,59 +13,72 @@ nothing."
;;; Gates and Operators: ;;; Gates and Operators:
(define-constant +unset-projector+ (define-constant +unset-projector+
#2A((1 0) #2A((1 0)
(0 0))) (0 0))
"|0><0| projector matrix.")
(define-constant +set-projector+ (define-constant +set-projector+
#2A((0 0) #2A((0 0)
(0 1))) (0 1))
"|1><1| projector matrix.")
(define-constant +identity-2x2+ (define-constant +identity-2x2+
(make-identity-matrix 2)) (make-identity-matrix 2)
"A 2 by 2 identity matrix.")
(define-constant +pauli-x-gate+ (define-constant +pauli-x-gate+
#2A((0 1) #2A((0 1)
(1 0))) (1 0))
"A 2 by 2 Pauli X gate that can be applied to a single qbit.")
(define-constant +pauli-y-gate+ (define-constant +pauli-y-gate+
#2A((0 #C(0 -1)) #2A((0 #C(0 -1))
(#C(0 -1) 0))) (#C(0 -1) 0))
"A 2 by 2 Pauli Y gate that can be applied to a single qbit.")
(define-constant +pauli-z-gate+ (define-constant +pauli-z-gate+
#2A((1 0) #2A((1 0)
(0 -1))) (0 -1))
"A 2 by 2 Pauli Z gate that can be applied to a single qbit.")
(define-constant +hadamard-gate+ (define-constant +hadamard-gate+
(let ((oort (/ (sqrt 2)))) (let ((oort (/ (sqrt 2))))
(make-array '(2 2) :initial-contents (make-array '(2 2) :initial-contents
`((,oort ,oort) `((,oort ,oort)
(,oort ,(- oort)))))) (,oort ,(- oort)))))
"A 2 by 2 Hadamard gate that can be applied to a single qbit.")
(define-constant +phase-gate+ (define-constant +phase-gate+
#2A((1 0) #2A((1 0)
(0 #C(0 1)))) (0 #C(0 1)))
"A 2 by 2 phase gate that can be applied to a single qbit.")
(define-constant +pi/8-gate+ (define-constant +pi/8-gate+
(make-array '(2 2) :initial-contents (make-array '(2 2) :initial-contents
`((1 0) `((1 0)
(0 ,(exp (complex 0 (/ pi 4))))))) (0 ,(exp (complex 0 (/ pi 4))))))
"A 2 by 2 phase gate that can be applied to a single qbit.")
(define-constant +cnot-gate+ (define-constant +cnot-gate+
#2A((1 0 0 0) #2A((1 0 0 0)
(0 1 0 0) (0 1 0 0)
(0 0 0 1) (0 0 0 1)
(0 0 1 0))) (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.")
(define-constant +cz-gate+ (define-constant +cz-gate+
#2A((1 0 0 0) #2A((1 0 0 0)
(0 1 0 0) (0 1 0 0)
(0 0 1 0) (0 0 1 0)
(0 0 0 -1))) (0 0 0 -1))
"A 4 by 4 controlled Pauli Z gate that applies to a 2 qbit state.")
(define-constant +swap-gate+ (define-constant +swap-gate+
#2A((1 0 0 0) #2A((1 0 0 0)
(0 0 1 0) (0 0 1 0)
(0 1 0 0) (0 1 0 0)
(0 0 0 1))) (0 0 0 1))
"A 4 by 4 swap gate that applies to a 2 qbit state.")
(define-constant +ccnot-gate+ (define-constant +ccnot-gate+
#2A((1 0 0 0 0 0 0 0) #2A((1 0 0 0 0 0 0 0)
@ -74,7 +88,9 @@ nothing."
(0 0 0 0 1 0 0 0) (0 0 0 0 1 0 0 0)
(0 0 0 0 0 1 0 0) (0 0 0 0 0 1 0 0)
(0 0 0 0 0 0 0 1) (0 0 0 0 0 0 0 1)
(0 0 0 0 0 0 1 0))) (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.")
;;; State Functions: ;;; State Functions:
(defun normal-state-p (state &key (places 5)) (defun normal-state-p (state &key (places 5))
@ -96,6 +112,13 @@ round the norm of STATE before checking."
"Return the number of bits in STATE." "Return the number of bits in STATE."
(values (ceiling (log (length state) 2)))) (values (ceiling (log (length state) 2))))
(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))
(defun make-normal-state (probabilities) (defun make-normal-state (probabilities)
"Create a new normalized state with the probability of each state "Create a new normalized state with the probability of each state
corresponding to an element in PROBABILITIES." corresponding to an element in PROBABILITIES."
@ -116,6 +139,11 @@ corresponding to an element in PROBABILITIES."
"Return the Nth index in a state in which BIT is 1." "Return the Nth index in a state in which BIT is 1."
(+ period (bit-unset-index bit n :period period))) (+ period (bit-unset-index bit n :period period)))
(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)))
(defun bit-probability (state bit) (defun bit-probability (state bit)
"Return the probability that BIT is set in STATE." "Return the probability that BIT is set in STATE."
(setq state (normalize-state state)) (setq state (normalize-state state))
@ -215,6 +243,39 @@ apply OPERATOR to TARGET if CONTROL is set."
(+mm (tensor-chain +identity-2x2+ +unset-projector+) (+mm (tensor-chain +identity-2x2+ +unset-projector+)
(tensor-chain operator +set-projector+)))) (tensor-chain operator +set-projector+))))
(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))
(defun replace-state (target template) (defun replace-state (target template)
"Replace each element of TARGET with the corresponding element in TEMPLATE." "Replace each element of TARGET with the corresponding element in TEMPLATE."
(assert (= (length target) (length template)) (assert (= (length target) (length template))
@ -223,20 +284,20 @@ apply OPERATOR to TARGET if CONTROL is set."
(dotimes (i (length target) target) (dotimes (i (length target) target)
(setf (aref target i) (aref template i)))) (setf (aref target i) (aref template i))))
(defun apply-operator (state operator target) (defun apply-gate (state operator target)
"Apply OPERATOR to the bit numbered TARGET in STATE." "Apply OPERATOR to the bit numbered TARGET in STATE."
(*mv (make-operator (state-bits state) operator target) state)) (*mv (make-operator (state-bits state) operator target) state))
(defun napply-operator (state operator target) (defun napply-gate (state operator target)
"Apply OPERATOR to the bit numbered TARGET in STATE. This modifies state." "Apply OPERATOR to the bit numbered TARGET in STATE. This modifies state."
(replace-state state (apply-operator state operator target))) (replace-state state (apply-gate state operator target)))
(defun apply-controlled-operator (state operator target control) (defun apply-controlled-gate (state operator target control)
"Apply OPERATOR to the bit numbered TARGET in STATE if CONTROL is set." "Apply OPERATOR to the bit numbered TARGET in STATE if CONTROL is set."
(*mv (make-controlled-operator (state-bits state) operator target control) (*mv (make-controlled-operator (state-bits state) operator target control)
state)) state))
(defun napply-controlled-operator (state operator target control) (defun napply-controlled-gate (state operator target control)
"Apply OPERATOR to the bit numbered TARGET in STATE if CONTROL is set. This "Apply OPERATOR to the bit numbered TARGET in STATE if CONTROL is set. This
modified STATE." modified STATE."
(replace-state state (apply-controlled-operator state operator target control))) (replace-state state (apply-controlled-gate state operator target control)))