114 lines
4.5 KiB
Common Lisp
114 lines
4.5 KiB
Common Lisp
(in-package :cl-quantum)
|
|
|
|
(defun pprint-complex (n &key parens)
|
|
"Pretty-print the complex (or real, rational, etc.) number N. If PARENS is
|
|
non-nil, surround the output with parenthesis if it is multiple terms."
|
|
(let* ((real (realpart n))
|
|
(imag (imagpart n))
|
|
;; Also put parenthesis on fractions to make them easier to read
|
|
(has-frac (and parens
|
|
(or (and (not (integerp real))
|
|
(rationalp real))
|
|
(and (not (integerp imag))
|
|
(rationalp imag))))))
|
|
(cond
|
|
((zerop n) "0")
|
|
((not (or (zerop real)
|
|
(zerop imag)))
|
|
(format nil "~@[~*(~]~a ~:[-~;+~] ~ai~@[~*)~]"
|
|
parens real (>= imag 0) (abs imag) parens))
|
|
(t
|
|
(format nil "~@[~*(~]~a~@[~*i~]~@[~*)~]"
|
|
has-frac (if (zerop real) imag real)
|
|
(zerop real) has-frac)))))
|
|
|
|
(defun pprint-format-bits (index size)
|
|
"A state formatter that converts the index to binary and pads it with zeros."
|
|
(format nil "~v,,,'0<~b~>" (ceiling (log size 2)) index))
|
|
|
|
(defun pprint-format-linear (index size)
|
|
"A state formatter that just returns the index +1 as a string."
|
|
(declare (ignorable size))
|
|
(format nil "~d" (1+ index)))
|
|
|
|
(defun pprint-state (state &key (formatter 'pprint-format-linear))
|
|
"Pretty-print STATE, a quantum state represented as an array. FORMATTER is a
|
|
function which takes the index of the quantum state and the total size of the
|
|
state. It should convert these to a printable representation. This
|
|
representation will be put inside of a ket after each coefficient."
|
|
(with-output-to-string (out)
|
|
(loop with need-sign = nil
|
|
for i below (length state)
|
|
for coef = (aref state i)
|
|
when (and need-sign (not (zerop coef)))
|
|
if (>= (realpart coef) 0)
|
|
do (format out " + ")
|
|
else
|
|
do (format out " - ")
|
|
and do (setq coef (* -1 coef))
|
|
end
|
|
end
|
|
unless (zerop coef)
|
|
do (format out "~a|~a>" (pprint-complex coef :parens t)
|
|
(funcall formatter i (length state)))
|
|
and do (setq need-sign t))))
|
|
|
|
(defconstant +parse-state-regexp+
|
|
(ppcre:create-scanner
|
|
"^\\s*([-+])?\\s*(\\()?\\s*([-+0-9ei./]*)\\s*(\\))?\\s*\\|([^>]*)>"
|
|
:extended-mode t)
|
|
"The regexp scanner used in `parse-state'.")
|
|
|
|
(defun parse-bits-state (state)
|
|
"A `parse-state' parser that parses its state as a binary string."
|
|
(parse-integer state :radix 2))
|
|
|
|
(defun parse-state (str &key (parser 'parse-integer))
|
|
"Try to parse STR into a quantum state. PARSER should be a function of one
|
|
argument that will take the string inside each ket and return the index of the
|
|
state."
|
|
(loop for start = 0 then (+ start (length whole))
|
|
for (whole matches) = (multiple-value-list
|
|
(ppcre:scan-to-strings +parse-state-regexp+
|
|
str
|
|
:sharedp t
|
|
:start start))
|
|
while whole
|
|
for coef = (if (zerop (length (aref matches 2)))
|
|
1
|
|
(parse-complex (aref matches 2)))
|
|
for index = (funcall parser (aref matches 4))
|
|
unless (eq (not (aref matches 1))
|
|
(not (aref matches 3)))
|
|
do (error "Mismatches parenthesis: ~s" whole)
|
|
when (and (complexp coef)
|
|
(not (aref matches 1)))
|
|
do (error "Coefficient without matching state: ~s" whole)
|
|
collect (if (equal (aref matches 0) "-")
|
|
(* -1 coef)
|
|
coef)
|
|
into coefs
|
|
collect index into indecies
|
|
maximizing (1+ index) into state-size
|
|
finally
|
|
(return
|
|
(let ((state (make-array state-size)))
|
|
(loop for index in indecies
|
|
for coef in coefs
|
|
do (incf (aref state index) coef))
|
|
state))))
|
|
|
|
(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)))
|
|
|
|
(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)))))
|