Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix EXPT printing #257

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cl-quil-tests.asd
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
(:file "initial-rewiring-tests")
(:file "lexer-tests")
(:file "parser-tests")
(:file "printer-tests")
(:file "classical-memory-tests")
(:file "resource-tests")
(:file "misc-tests")
Expand Down
1 change: 1 addition & 0 deletions cl-quil.asd
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
:components ((:static-file "stdgates.quil")))
(:file "package")
(:file "options")
(:file "types")
(:file "utilities")
(:file "relabeling")
(:file "matrix-operations")
Expand Down
7 changes: 2 additions & 5 deletions src/addresser/rewiring.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@

(in-package #:cl-quil)

(defun integeropt-vector-p (v)
(and (vectorp v) (every (lambda (x) (or (not x) (integerp x))) v)))

(defstruct (rewiring
(:constructor init-rewiring)
(:copier nil))
(l2p #() :type (satisfies integeropt-vector-p))
(p2l #() :type (satisfies integeropt-vector-p)))
(l2p #() :type integeropt-vector)
(p2l #() :type integeropt-vector))

(defun inverse-matches-forward-p (forward inverse)
"Checks that each non-NIL mapping in FORWARD has a corresponding inverse mapping in
Expand Down
31 changes: 21 additions & 10 deletions src/ast.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,17 @@ EXPRESSION should be an arithetic (Lisp) form which refers to LAMBDA-PARAMS."

(defun make-delayed-expression (params lambda-params expression)
"Make a DELAYED-EXPRESSION object initially with parameters PARAMS (probably a list of PARAM objects), lambda parameters LAMBDA-PARAMS, and the form EXPRESSION."
(assert (every #'symbolp lambda-params))
ecpeterson marked this conversation as resolved.
Show resolved Hide resolved
(check-type lambda-params symbol-list)
(%delayed-expression :params params
:lambda-params lambda-params
:expression expression))

(defun evaluate-delayed-expression (de &optional (memory-model-evaluator #'identity))
"Evaluate the delayed expression DE to a numerical value (represented in a CONSTANT data structure). MEMORY-MODEL is an association list with keys MEMORY-REF structures and values the value stored at that location."
(labels ((lookup-function (expr)
(case expr
((+ - * / cos sin tan) expr)
(otherwise (error "Illegal function in arithmetic expression: ~a." expr))))
(if (valid-quil-function-or-operator-p expr)
expr
(error "Illegal function in arithmetic expression: ~a." expr)))
(evaluate-parameter (param)
(etypecase param
(constant (constant-value param))
Expand All @@ -122,7 +122,7 @@ EXPRESSION should be an arithetic (Lisp) form which refers to LAMBDA-PARAMS."
(cons
(let ((args (mapcar (lambda (e) (evaluate-expr params lambda-params e))
(cdr expression))))
(if (every (lambda (thing) (typep thing 'number)) args)
(if (number-list-p args)
(apply (lookup-function (first expression)) args)
(cdr expression))))
(symbol
Expand Down Expand Up @@ -152,9 +152,20 @@ EXPRESSION should be an arithetic (Lisp) form which refers to LAMBDA-PARAMS."

;;;;;;;;;;;;;;;;;;;;; Comment protocol for syntax tree objects ;;;;;;;;;;;;;;;;;;;;

(eval-when (:compile-toplevel :load-toplevel :execute)
(defun make-comment-table ()
ecpeterson marked this conversation as resolved.
Show resolved Hide resolved
"Return an empty weak hash table suitable for use as the CL-QUIL::**COMMENTS** table.

This function can be used to re-initialize the **COMMENTS** table.

Keys are tested with EQ."
(tg:make-weak-hash-table :test 'eq :weakness ':key)))

(global-vars:define-global-var **comments**
(tg:make-weak-hash-table :test 'eq :weakness ':key)
"Weak hash table populated with comments associated to different parts of an AST.")
(make-comment-table)
"Weak hash table populated with comments associated to different parts of an AST.

The keys are typically INSTRUCTION instances and associated values are STRINGs.")

(defun comment (x)
(values (gethash x **comments**)))
Expand Down Expand Up @@ -250,7 +261,7 @@ as a permutation."
(defun make-gate-definition (name parameters entries)
"Make a static or parameterized gate definition instance, depending on the existence of PARAMETERS."
(check-type name string)
(assert (every #'symbolp parameters))
(check-type parameters symbol-list)
(if parameters
(make-instance 'parameterized-gate-definition
:name name
Expand Down Expand Up @@ -1151,11 +1162,11 @@ For example,
((= (length expr) 3)
(format stream "(~a~a~a)"
(print-delayed-expression (second expr) nil)
(first expr)
(lisp-symbol->quil-infix-operator (first expr))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we don't check for a valid operator here first (likewise just below). We are relying on the fact that the delayed-expression for sure 💯% has a lisp symbol that maps to a valid Quil operator in the CAR and not, say, CL:GET-INTERNAL-RUN-TIME. If lookup fails, lisp-symbol->quil-infix-operator will just return NIL.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason not to throw an error in l-s->q-i-o if it tries to lookup a nonexistent key? That seems like a sane enough thing to do to me.

Copy link
Contributor Author

@appleby appleby Jun 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be possible, though it would complicate the implementation valid-quil-function-or-operator-p, which currently just tries all the lookup functions in order.

(defun valid-quil-function-or-operator-p (symbol)
    (not (null (or (lisp-symbol->quil-function symbol)
                   (lisp-symbol->quil-prefix-operator symbol)
                   (lisp-symbol->quil-infix-operator symbol)))))

In general, when adding an abstraction layer like this, I like to keep it purely functional if possible and allow the caller to decide how to handle errors if they want to. For example, if parsing fails, you probably want to signal a "parse-error", but in other places, maybe a different error.

I did consider adding another set of functions with the same name but with -or-error or -or-lose or some such appended, and using it here. In this case, that would map to lisp-symbol->quil-infix-operator-or-error, to make it easy for callers that are not bothered about a custom error condition. I suppose the on-error variants could allow the caller to pass in the condition they want on failure.

Edit: s/are bothered/are not bothered/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyone worried enough they want to see error checking here before merge? I suppose another option is to let the caller specify via keyword argument what behavior they want on lookup failure, i.e.: 1) return nil, 2) default error, 3) custom condition.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 worries here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 worries here

mplayer ~/music/bob-marley/three-little-birds.mp3

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 worries here

mplayer ~/music/bob-marley/three-little-birds.mp3

Classic @appleby

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 worries here

mplayer ~/music/bob-marley/three-little-birds.mp3

Classic @appleby

Phew. For a second there I was worried no one would get the joke.

(print-delayed-expression (third expr) nil)))
((= (length expr) 2)
(format stream "~a(~a)"
(first expr)
(lisp-symbol->quil-function-or-prefix-operator (first expr))
(print-delayed-expression (second expr) nil)))))
(number
(format stream "(~/cl-quil:complex-fmt/)" expr))
Expand Down
5 changes: 1 addition & 4 deletions src/chip-reader.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,12 @@
(:documentation "This condition can be signaled when the chip reader fails to find an ISA layer.")
(:report "Invalid QPU description file: missing required ISA layer or sub-layer."))

(defun integer-list-p (list)
(every #'integerp list))

(defun expand-key-to-integer-list (key)
"Expands a string of the form \"n1-...-nm\" to the list of integers (list n1 ... nm)."
(etypecase key
(string
(mapcar #'parse-integer (split-sequence:split-sequence #\- key)))
((and list (satisfies integer-list-p))
(integer-list
key)))

(defun dead-qubit-hash-table ()
Expand Down
4 changes: 2 additions & 2 deletions src/clifford/clifford.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ qubits."
(declaim (ftype (function (t) simple-vector) basis-map))
(defstruct (clifford (:include qubit-algebra))
"An element of the Clifford group on NUM-QUBITS qubits."
(num-qubits 0 :type unsigned-fixnum)
(num-qubits 0 :type quil::unsigned-fixnum)
(basis-map nil :type simple-vector))

(defmethod num-qubits ((c clifford))
Expand Down Expand Up @@ -236,7 +236,7 @@ NOTE: THERE IS NO CHECKING OF THE VALIDITY OF THE MAP. ANTICOMMUTATIVITY IS NOT
(declare (type clifford c))
(declare (inline pauli-hash))
(sxhash
(loop :with h :of-type unsigned-fixnum := 0
(loop :with h :of-type quil::unsigned-fixnum := 0
:for p :of-type pauli :across (basis-map c)
:do (setf h (hash-mix h (pauli-hash p)))
:finally (return h))))
Expand Down
4 changes: 2 additions & 2 deletions src/clifford/pauli.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
(1- (length (pauli-components p))))

(defun make-components (num-qubits)
(declare (type unsigned-fixnum num-qubits))
(declare (type quil::unsigned-fixnum num-qubits))
(make-array (1+ num-qubits) :element-type 'base4
:initial-element 0))

Expand Down Expand Up @@ -265,7 +265,7 @@ hash-function."
(declare (optimize speed (safety 0) (debug 0) (space 0))
(type pauli p))
(sxhash
(loop :with h :of-type unsigned-fixnum := 0
(loop :with h :of-type quil::unsigned-fixnum := 0
:for x :across (pauli-components p)
:do (setf h (hash-mix h x))
:finally (return h))))
Expand Down
3 changes: 0 additions & 3 deletions src/clifford/qubit-algebra.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
;;; algebras", corresponding to algebras that have some correspondence
;;; with collections of qubits.

(deftype unsigned-fixnum ()
`(and fixnum unsigned-byte))

(defstruct (qubit-algebra (:conc-name nil))
"A generic algebra involving objects specialized to NUM-QUBITS qubits.")

Expand Down
2 changes: 1 addition & 1 deletion src/compilers/approx.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
;; special-orthogonal, we have to correct this behavior manually.
(defun find-real-spanning-set (vectors)
"VECTORS is a list of complex vectors in C^n (which, here, are of type LIST). When possible, computes a set of vectors with real coefficients that span the same complex subspace of C^n as VECTORS."
(assert (a:proper-list-p vectors))
(check-type vectors a:proper-list)
(let* ((coeff-matrix (magicl:make-complex-matrix
(length (first vectors))
(* 2 (length vectors))
Expand Down
10 changes: 0 additions & 10 deletions src/define-pragma.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,6 @@ elements to ELT-TYPE.
(alexa:lexer-match-error (c)
(quil-parse-error "Lexer failure: ~A" c))))

(defun integer-sequence-p (object)
(and (typep object 'sequence)
(every #'integerp object)))

(deftype integer-vector ()
ecpeterson marked this conversation as resolved.
Show resolved Hide resolved
`(and vector (satisfies integer-sequence-p)))

(deftype integer-list ()
`(and list (satisfies integer-sequence-p)))


;;;;;;;;;;;;;;;;;;;; Macroexpansion-time checking ;;;;;;;;;;;;;;;;;;;;

Expand Down
2 changes: 1 addition & 1 deletion src/gates.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@
(entries (gate-definition-entries gate-def))
(params (gate-definition-parameters gate-def))
(dim (isqrt (length entries))))
(assert (every #'symbolp params))
(check-type params symbol-list)
(make-instance 'parameterized-gate
:name name
:dimension dim
Expand Down
128 changes: 109 additions & 19 deletions src/parser.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -1515,25 +1515,113 @@ INPUT-STRING that triggered the condition."
(token-payload tok))))))

(eval-when (:compile-toplevel :load-toplevel :execute)
(a:define-constant +quil<->lisp-functions+
'(("SIN" . cl:sin)
("COS" . cl:cos)
("SQRT" . cl:sqrt)
("EXP" . cl:exp)
("CIS" . cl:cis))
:test #'equal
:documentation
"Functions usable from within Quil, and their associated Lisp function symbols.")

;;; If you add a new arithmetic operator to +QUIL<->LISP-PREFIX-ARITHMETIC-OPERATORS+ or
;;; +QUIL<->LISP-INFIX-ARITHMETIC-OPERATORS+, you must also add it to *ARITHMETIC-GRAMMAR*, below.
(a:define-constant +quil<->lisp-prefix-arithmetic-operators+
'(("-" . cl:-))
:test #'equal
:documentation
"Prefix arithmetic operators usable from within Quil, and their associated Lisp function symbols.")

(a:define-constant +quil<->lisp-infix-arithmetic-operators+
'(("+" . cl:+)
("-" . cl:-)
("/" . cl:/)
("*" . cl:*)
("^" . cl:expt))
:test #'equal
:documentation
"Infix arithmetic operators usable from within Quil, and their associated Lisp function symbols.")

(defun %lisp->quil (lisp-symbol alist)
(check-type lisp-symbol symbol)
(a:when-let ((found (rassoc lisp-symbol alist :test #'eq)))
(car found)))

(defun %quil->lisp (quil-string alist)
(check-type quil-string string)
(a:when-let ((found (assoc quil-string alist :test #'string-equal)))
(cdr found)))

;;; The following functions handle conversion between Quil's arithmetic operators/functions and
;;; the corresponding lisp symbols (fbound to lisp functions) that are used in CL-QUIL for
;;; evaluating Quil's arithmetic expressions. The mapping from lisp->Quil and Quil->lisp is
;;; determined by the above tables, namely: +QUIL<->LISP-FUNCTIONS+,
;;; +QUIL<->LISP-PREFIX-ARITHMETIC-OPERATORS+, and +QUIL<->LISP-INFIX-ARITHMETIC-OPERATORS+.
;;;
;;; For example, the Quil infix operator "/" in an expression like "pi/8" maps to the Common Lisp
;;; symbol CL:/ and vice versa. Likewise for the prefix operator "-" in "-%theta" which maps to
;;; CL:-.
;;;
;;; The purpose of the following functions is to provide a layer of abstraction around the
;;; conversion to/from Quil<->lisp and to act as a single source of truth for such conversions.
;;;
;;; Here is a glossary of the terms used in the following function names:
;;;
;;; lisp-symbol:
;;; a SYMBOL which is fbound to a lisp function appropriate for evaluating the corresponding
;;; Quil function or arithmetic operator.
;;;
;;; quil-function:
;;; a STRING that denotes a Quil arithmetic function. For example "SIN", "COS", "EXP", etc.
;;; See the table +QUIL<->LISP-FUNCTIONS+ for the list of valid functions.
;;;
;;; quil-prefix-operator:
;;; a STRING that denotes a Quil prefix (unary) arithmetic operator. For example, the "-" in
;;; the expression "-pi/2". See the table +QUIL<->LISP-PREFIX-ARITHMETIC-OPERATORS+ for the
;;; list of valid prefix operators.
;;;
;;; quil-infix-operator:
;;; a STRING that denotes a Quil infix (binary) arithmetic operator. For example, the "-" in
;;; the expression "COS(%x) - i * SIN(%x)". See +QUIL<->LISP-INFIX-ARITHMETIC-OPERATORS+ for
;;; the list of valid infix operators.

ecpeterson marked this conversation as resolved.
Show resolved Hide resolved
(defun lisp-symbol->quil-prefix-operator (symbol)
(%lisp->quil symbol +quil<->lisp-prefix-arithmetic-operators+))

(defun quil-prefix-operator->lisp-symbol (quil-prefix-operator)
(%quil->lisp quil-prefix-operator +quil<->lisp-prefix-arithmetic-operators+))

(defun lisp-symbol->quil-infix-operator (symbol)
(%lisp->quil symbol +quil<->lisp-infix-arithmetic-operators+))

(defun quil-infix-operator->lisp-symbol (quil-infix-operator)
(%quil->lisp quil-infix-operator +quil<->lisp-infix-arithmetic-operators+))

(defun lisp-symbol->quil-function (symbol)
(%lisp->quil symbol +quil<->lisp-functions+))

(defun quil-function->lisp-symbol (quil-function)
(%quil->lisp quil-function +quil<->lisp-functions+))

(defun lisp-symbol->quil-function-or-prefix-operator (symbol)
(or (lisp-symbol->quil-function symbol)
(lisp-symbol->quil-prefix-operator symbol)))

(defun valid-quil-function-or-operator-p (symbol)
(not (null (or (lisp-symbol->quil-function symbol)
(lisp-symbol->quil-prefix-operator symbol)
(lisp-symbol->quil-infix-operator symbol)))))

(defun binary (head)
(lambda (a i0 b)
(declare (ignore i0))
(list head a b)))

(defparameter *valid-functions*
'(("SIN" cl:sin)
("COS" cl:cos)
("SQRT" cl:sqrt)
("EXP" cl:exp)
("CIS" cl:cis))
"Functions usable from within Quil, and their associated Lisp function symbols.")

(defun validate-function (func-name)
"Validate the function named FUNC-NAME against *VALID-FUNCTIONS*. Signal a QUIL-PARSE-ERROR if it's invalid."
(let ((found (assoc func-name *valid-functions* :test #'string-equal)))
(if found
(second found)
(quil-parse-error "Invalid function name: ~A" func-name))))
"Return the lisp symbol that corresponds to the Quil function named FUNC-NAME, or signal a QUIL-PARSE-ERROR if FUNC-NAME is invalid."
(or (quil-function->lisp-symbol func-name)
(quil-parse-error "Invalid function name: ~A" func-name)))

(defun find-or-make-parameter-symbol (param)
(let ((found (assoc (param-name param)
Expand Down Expand Up @@ -1563,18 +1651,20 @@ INPUT-STRING that triggered the condition."
(:precedence ((:right :EXPT) (:left :TIMES :DIVIDE) (:left :PLUS :MINUS)))

(expr
(expr :PLUS expr (binary 'cl:+))
(expr :MINUS expr (binary 'cl:-))
(expr :TIMES expr (binary 'cl:*))
(expr :DIVIDE expr (binary 'cl:/))
(expr :EXPT expr (binary 'cl:expt))
;; If you add a new arithmetic operator here, you must also add it to
;; +quil<->lisp-infix-arithmetic-operators+, above.
(expr :PLUS expr (binary (quil-infix-operator->lisp-symbol "+")))
(expr :MINUS expr (binary (quil-infix-operator->lisp-symbol "-")))
(expr :TIMES expr (binary (quil-infix-operator->lisp-symbol "*")))
(expr :DIVIDE expr (binary (quil-infix-operator->lisp-symbol "/")))
(expr :EXPT expr (binary (quil-infix-operator->lisp-symbol "^")))
term)

(term
(:MINUS expr
(lambda (i0 x)
(declare (ignore i0))
(list 'cl:- x)))
(list (quil-prefix-operator->lisp-symbol "-") x)))
(:NAME :LEFT-PAREN expr :RIGHT-PAREN
(lambda (f i0 x i1)
(declare (ignore i0 i1))
Expand Down
Loading