polycirc.operation
The primitive circuits from which arithmetic circuits are built.
Each Operation
can have multiple inputs and outputs.
For example, if we call the Copy
operation as a function, we can see it repeats its input:
>>> from polycirc.ast import diagram_to_ast
>>> f = diagram_to_ast(Copy().diagram(), 'copy').to_function()
>>> f(314)
[314, 314]
Since Copy
has one input and two outputs, its type is 1 → 2
>>> Copy().type
(1, 2)
Similarly, the Add
operation adds its inputs:
>>> from polycirc.ast import diagram_to_ast
>>> f = diagram_to_ast(Add().diagram(), 'add').to_function()
>>> f(314, 1)
[315]
A diagram built from these primitives is like a circuit whose wires carry values in some semiring S. Note that the set of primitives included is also functionally complete. For further mathematical details, refer to Wilson and Zanasi [WZ22].
Polycirc currently supports the following primitive operations:
Operation |
Type |
Function |
---|---|---|
Add |
2→1 |
[x₁+x₂] |
Negate |
1→1 |
[-x₁] |
Constant(c) |
0→1 |
[c] |
Copy |
1→2 |
[x₁, x₁] |
Discard |
1→0 |
[] |
Sub |
2→1 |
[x₁-x₂] |
Mul |
2→1 |
[x₁*x₂] |
Shr |
2→1 |
[x₁ >> x₂] |
Eq |
2→1 |
[int(x₁ == x₂)] |
Gt |
2→1 |
[int(x₁ > x₂)] |
Geq |
2→1 |
[int(x₁ >= x₂)] |
Lt |
2→1 |
[int(x₁ < x₂)] |
Leq |
2→1 |
[int(x₁ <= x₂)] |
- class polycirc.operation.Operation
- abstract property type: Tuple[int, int]
The number of inputs and outputs
- property source
- property target
- abstract property fwd: Diagram
the forward map of this operation as a Diagram
- abstract property rev: Diagram
the reverse map of this operation as a Diagram. This generally corresponds to its reverse derivative.
- abstract property residual: Diagram
- diagram()
Return the operation as a singleton diagram
- class polycirc.operation.LinearOperation
An Operation with an empty residual
- fwd() Diagram
the forward map of this operation as a Diagram
- rev() Diagram
the reverse map of this operation as a Diagram. This generally corresponds to its reverse derivative.
- residual()
- abstract dagger() Diagram
For an operation
op
of type A → B, its daggerop.dagger()
must have typeB → A
.