(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)))))