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

Adds a coalton AST for Quil #925

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft

Adds a coalton AST for Quil #925

wants to merge 7 commits into from

Conversation

macrologist
Copy link
Contributor

@macrologist macrologist commented Sep 24, 2024

This is a fairly complete recreation of src/ast.lisp in coalton.

There are a few uncertainties that could be resolved provided feedback about use-cases.

  1. I have tried to make the syntax as "flat" as possible. However there are some perhaps ugly "wrappers", namely:
  • the (ApplyGate (Gate :num)) instruction
  • the (ApplyOp ClassicalOperation) instruction
  • the (MaybeFormal :t) wrapper type used to wrap arguments to application instructions.
  1. I may have gone overboard (while at the same time not being strict enough, so a lose-lose) when cramming Quil's arithmetic expressions into a ADT. If this is to be useful for humans, further work might be done, or, the ADT scrapped in favor of stringly expressions to be parsed.
  2. The representation of Forked gates does not sit well with me, but I couldn't think of anything cleaner. Forked is syntactically bizarre in that, unlike other operators, the gate-representing forms to which Forked is applied are not, from a certain point of view, grammatically valid on their own.
  3. It is entirely possible to construct bad programs, even with the benefit of the ADT. Most of the "room for screwing up" comes in the freedom to input formal arguments when concrete arguments are required.
  4. Instruction and Expr are parameterized by a free type :num, intended to capture a number representation. Right now that type is totally unconstrained in all interfaces. It should probably be constrained by Real so that instances of :num values can be approximated during the construction of the raw cl-quil types. However, doing so introduces complication in those cases where complex numbers may appear, namely in the entries to some gate definitions.
  5. The Instruction type allows for the construction of malformed programs that include:
  • nested DEFCIRCUITs
  • the presence of quil:formals in instructions that ought to require concrete qubits or memory references
  • the nesting of DEFGATEs in DEFCIRCUITs

Item 6 could be mitigated with the addition of a new type MacroInstruction or something that restricts the types of instructions that may appear inside of DEFCIRCUITs. Having such a MacroInstruction type would also allow for the removal of MaybeFormal wrapped types in several places. I did end up doing this.

Here's an example of "use"


> (coalton
                  (let ((m (mem:single "m" mem:QuilBit)))
                    (build-resolved-program
                     (make-list
                      (ast:Pragma "INITIAL_REWIRING \"NAIVE\"")
                      (ast:DeclareMem m)
                      (ast:ApplyGate (gate:H 0))
                      (ast:ApplyGate (gate:CNOT 0 1))
                      (ast:Measure 1 (mem:ref-to m))
                      (ast:ApplyOp (op:XOR (op:Mem (mem:ref-to m))
                                           (op:Const 1)))))))
#<QUIL:PARSED-PROGRAM of 5 instructions {70083CCCC3}>

> (cl:inspect cl:*)

The object is a STANDARD-OBJECT of type QUIL:PARSED-PROGRAM.
0. TRANSFORMS: (QUIL:TYPE-CHECK QUIL:EXPAND-CIRCUITS
                                QUIL::VALIDATE-DEFGATE-LOOPS)
1. GATE-DEFINITIONS: COMMON-LISP:NIL
2. CIRCUIT-DEFINITIONS: COMMON-LISP:NIL
3. MEMORY-DEFINITIONS: (#S(QUIL:MEMORY-DESCRIPTOR
                           :NAME "m"
                           :TYPE #.QUIL:QUIL-BIT
                           :LENGTH 1
                           :SHARING-PARENT COMMON-LISP:NIL
                           :SHARING-OFFSET-ALIST COMMON-LISP:NIL
                           :LEXICAL-CONTEXT COMMON-LISP:NIL))
4. EXECUTABLE-PROGRAM: #(#<PRAGMA INITIAL_REWIRING "NAIVE"> #<H 0> #<CNOT 0 1>
                         #<MEASURE 1 m[0]> #<XOR m[0] 1>)
5. EXTERN-OPERATIONS: #<COMMON-LISP:HASH-TABLE :TEST COMMON-LISP:EQUAL :COUNT 0 {70083CC993}>
> 

Before I produced a test suite, I wanted to get some feedback about use and general style. Marking as draft for now.

@macrologist
Copy link
Contributor Author

@YarinHeffes have a look if you feel like it.

the introduction of the macro module includes a subeset of
instructions from the unresolved module. macro instrutions can accept
formal arguments. They were made in order to distinguish instructions
that can appear within DEFCIRCUITS from those that appear in
executable code.

Classical instructions have also been given a numeric type argument
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant