polycirc.ast
Compile diagrams to abstract syntax trees (AST) and python functions. For example:
>>> import polycirc.ir as ir
>>> d = ir.add(1) >> ir.negate(1) # diagram representing -(x + y)
>>> a = diagram_to_ast(d, 'fn') # convert the diagram to an AST
>>> fn = a.to_function() # compile the AST to a python function
>>> fn(1, 2) # run the function
[-3]
Note
This module isn’t intended as a way to construct circuits directly.
Instead, build diagrams with polycirc.ir
, and compile them to the
AST form with diagram_to_ast()
.
In more detail:
diagram_to_ast()
converts aDiagram
to an abstract syntax tree whose top level node is aFunctionDefinition
.FunctionDefinition
is an AST with:a name …
a list of named inputs…
… outputs
and a list of internal
Assignment
statements
A
FunctionDefinition
a
can be compiled to a callable python function witha.to_function()
.diagram_to_function()
is a helper function to compile a diagram to a function directly
Note that in contrast to a usual AST representation, the classes in this module
are not recursive.
The role normally played by recursion is instead handled by the combinatorial
structure of Yarrow’s Diagram
datastructure, which might be thought of as a
kind of “flattened” AST.
The AST representation here is correspondingly “flat”: a
FunctionDefinition
is essentially just a list of assignment
statements of the form var = var | constant | binary op | unary op
, and
operations can only refer to names or constants.
- class polycirc.ast.ASTNode
The base class of AST nodes
- class polycirc.ast.UnaryOp(op: Operation, rhs: Name | Constant)
Unary operations (like negation
-x
)
- class polycirc.ast.BinOp(lhs: Name | Constant, op: Operation, rhs: Name | Constant)
A binary operation
- class polycirc.ast.Expr
Expression nodes evaluate to a single value. Note that Expr is not recursive: nested operations like
x0 = (x1 + x2) + x3
cannot be represented.
- class polycirc.ast.Assignment(lhs: Name, rhs: Expr)
An Assignment sets a variable’s value to an expression. For example
x₀ = x₁ * 2
- class polycirc.ast.FunctionDefinition(function_name: Name, args: List[Name], body: List[Assignment], returns: List[Name])
The top-level node of an expression tree. This essentially wraps a list of assigments of expressions to variables.
>>> from polycirc.operation import Add >>> name = 'foo' >>> x0, x1, x2 = [ Name(x) for x in ["x0", "x1", "x2"] ] >>> args = [x0, x1] >>> body = [Assignment(x2, BinOp(x0, Add(), x1))] >>> returns = [x2] >>> print(FunctionDefinition(name, args, body, returns), end='') def foo(x0, x1): x2 = x0 + x1 return [x2]
- body: List[Assignment]
- to_function(filename='<string>')
Use python’s ‘compile’ to turn this AST into a python function
- polycirc.ast.make_name(i: int)
Turn an integer i into the string
"x{i}"
>>> make_name(2) Name(id='x2')
- polycirc.ast.op_to_assignments(op: Operation, args, coargs) List[Assignment]
Convert an Operation and its source and target hypernodes into a list of Assignment statements
- polycirc.ast.diagram_to_ast(d: Diagram, function_name: str) FunctionDefinition
Turn a yarrow Diagram into a FunctionDefinition by decomposing it acyclically
- polycirc.ast.diagram_to_function(d: Diagram, function_name: str = 'fn')
Turn a diagram directly into a callable python function.