Operations Reference
Detailed reference for all atomic operations and combinators in Asgard circuits.
Operation Categories
| Category | Operations | Purpose |
|---|---|---|
| Arithmetic | add, multiplication, scalar |
Mathematical operations |
| Structure | id, split, const, var |
Circuit structure |
| Differential | register, deregister |
Integration and differentiation |
| Combinators | composition, monoidal, trace |
Circuit composition |
Combinators
composition(f, g)
Signature: If f : A → B and g : B → C, then composition(f, g) : A → C
Description: Sequential composition - apply f first, then g.
Category Theory: Morphism composition in the circuit category.
Example:
# Fundamental theorem: d/dx(∫f dx) = f
circuit = Circuit.from_string("composition(register(x), deregister(x))")
Execution Semantics:
outputs_f, state_1 = f(inputs, state_0)
outputs_g, state_2 = g(outputs_f, state_1)
return outputs_g, state_2
Identity Laws:
composition(f, id) ≡ f # Right identity
composition(id, f) ≡ f # Left identity
Associativity:
composition(f, composition(g, h)) ≡ composition(composition(f, g), h)
monoidal(f, g)
Signature: If f : A → B and g : C → D, then monoidal(f, g) : A⊕C → B⊕D
Description: Parallel composition - apply f and g independently.
Category Theory: Tensor product in monoidal category.
Example:
# Apply different scalars to two inputs
circuit = Circuit.from_string("monoidal(scalar(2.0), scalar(3.0))")
Execution Semantics:
inputs_f = inputs[:n] # First n inputs
inputs_g = inputs[n:] # Remaining m inputs
outputs_f, state_f = f(inputs_f, state)
outputs_g, state_g = g(inputs_g, state)
outputs = concatenate([outputs_f, outputs_g])
return outputs, state_g
Interchange Law:
composition(
monoidal(f, g),
monoidal(h, k)
) ≡ monoidal(
composition(f, h),
composition(g, k)
)
trace(f)
Signature: If f : A⊕X → B⊕X, then trace(f) : A → B
Description: Feedback loop - connect last output back to last input.
Category Theory: Trace operator in traced monoidal category.
Example:
# Solve differential equation via feedback
circuit = Circuit.from_string(
"trace(composition(monoidal(id, register(t)), add))"
)
Execution Semantics (Fixed-point iteration):
feedback = initialize_feedback() # Usually zeros
for i in range(max_iterations=100):
all_inputs = concatenate([inputs, feedback])
all_outputs, state = f(all_inputs, state)
regular_outputs = all_outputs[:-1]
new_feedback = all_outputs[-1]
if converged(feedback, new_feedback, tolerance=1e-6):
return regular_outputs, state
feedback = new_feedback
Use Cases:
- Differential equations:
dy/dt = f(y)viay = ∫f(y) - Recursive definitions
- Control systems with feedback
Arithmetic Operations
add
Signature: 2 → 1
Description: Element-wise addition of two streams.
Syntax:
circuit = Circuit.from_string("add")
Behavior:
Input 1: [a₀, a₁, a₂, ...]
Input 2: [b₀, b₁, b₂, ...]
Output: [a₀+b₀, a₁+b₁, a₂+b₂, ...]
Example:
from gimle.asgard.circuit.circuit import Circuit
from gimle.asgard.runtime.stream import Stream, StreamState
import jax.numpy as jnp
circuit = Circuit.from_string("add")
input1 = Stream(data=jnp.array([[1.0, 2.0, 3.0]]), dim_labels=(), chunk_size=1)
input2 = Stream(data=jnp.array([[4.0, 5.0, 6.0]]), dim_labels=(), chunk_size=1)
outputs, state = circuit.execute([input1, input2], StreamState())
# Output: [5.0, 7.0, 9.0]
multiplication
Signature: 2 → 1
Description: Element-wise multiplication of two streams.
Syntax:
circuit = Circuit.from_string("multiplication")
Behavior:
Input 1: [a₀, a₁, a₂, ...]
Input 2: [b₀, b₁, b₂, ...]
Output: [a₀·b₀, a₁·b₁, a₂·b₂, ...]
Use Cases:
- Multiplying functions
- Scaling by variable functions
- Implementing nonlinear terms
scalar(c)
Signature: 1 → 1
Description: Multiply all elements by a constant scalar.
Syntax:
circuit = Circuit.from_string("scalar(2.5)")
Parameters:
c(float): Scaling constant
Behavior:
Input: [a₀, a₁, a₂, ...]
Output: [c·a₀, c·a₁, c·a₂, ...]
Example:
circuit = Circuit.from_string("scalar(2.0)")
input_stream = Stream(data=jnp.array([[1.0, 2.0, 3.0]]), dim_labels=(), chunk_size=1)
outputs, state = circuit.execute([input_stream], StreamState())
# Output: [2.0, 4.0, 6.0]
Structure Operations
id
Signature: 1 → 1
Description: Identity operation - passes input unchanged.
Syntax:
circuit = Circuit.from_string("id")
Behavior:
Input: [a₀, a₁, a₂, ...]
Output: [a₀, a₁, a₂, ...]
Use Cases:
- No-op in circuit composition
- Placeholder in monoidal products
- Identity element in category theory
split
Signature: 1 → 2
Description: Duplicates the input to create two identical outputs (fanout).
Syntax:
circuit = Circuit.from_string("split")
Behavior:
Input: [a₀, a₁, a₂, ...]
Output 1: [a₀, a₁, a₂, ...]
Output 2: [a₀, a₁, a₂, ...]
Example:
# Square a value: x → [x, x] → x * x
circuit = Circuit.from_string("composition(split, multiplication)")
Status: Stub implementation
const(c)
Signature: 0 → 1
Description: Generates a constant stream (ignores inputs).
Syntax:
circuit = Circuit.from_string("const(3.14)")
Parameters:
c(float): Constant value
Behavior:
(no input)
Output: [c, 0, 0, 0, ...] # Constant in first coefficient
Use Cases:
- Generating constant terms
- Initial conditions
- Fixed parameters
var(name)
Signature: 1 → 1
Description: Variable lookup or identity.
Syntax:
circuit = Circuit.from_string("var(x)")
Parameters:
name(str): Variable name
Behavior:
# If var_values = {"x": 5.0}:
Input: [a₀, a₁, a₂, ...]
Output: [5.0, 0, 0, ...]
# If "x" not in var_values:
Input: [a₀, a₁, a₂, ...]
Output: [a₀, a₁, a₂, ...] # Identity
Differential Operations
register(dim)
Signature: 1 → 1
Description: Integration along a dimension (shifts coefficients right).
Syntax:
circuit = Circuit.from_string("register(x)")
Parameters:
dim(str): Dimension label to integrate along
Behavior:
Input: [a, b, c]
Output: [0, a, b] # Shift right, pad with 0
Mathematical Meaning by Calculus:
| Calculus | Operation | Formula |
|---|---|---|
| RealCalculus | Indefinite integral | ∫f(x)dx |
| StochasticCalculus | Stochastic integral | ∫f dW_t |
| DiscreteCalculus | Cumulative sum | Σf(n) |
Stateful: Yes - saves last element as boundary for next chunk
Example:
# Integration: ∫x dx = x²/2
# Coefficients: x = [0, 1] → ∫x dx = [0, 0, 1]
circuit = Circuit.from_string("register(x)")
deregister(dim)
Signature: 1 → 1
Description: Differentiation along a dimension (shifts coefficients left).
Syntax:
circuit = Circuit.from_string("deregister(x)")
Parameters:
dim(str): Dimension label to differentiate along
Behavior:
Input: [a, b, c]
Output: [b, c] # Shift left, drop first
Mathematical Meaning by Calculus:
| Calculus | Operation | Formula |
|---|---|---|
| RealCalculus | Derivative | df/dx |
| StochasticCalculus | Ill-defined | (Brownian motion non-differentiable) |
| DiscreteCalculus | Finite difference | Δf(n) = f(n+1) - f(n) |
Stateful: No - differentiation loses information
Example:
# Differentiation: d/dx(x²) = 2x
# Coefficients: x² = [0, 0, 2] → d/dx = [0, 4]
circuit = Circuit.from_string("deregister(x)")
Performance Characteristics
| Operation | Complexity | Notes |
|---|---|---|
add, multiplication |
O(n) | Element-wise, highly parallel |
scalar, id, var |
O(n) | Trivial operations |
const |
O(1) | Constant generation |
register, deregister |
O(n) | Array slicing/concatenation |
split |
O(n) | Memory copy (JAX optimizes) |
composition |
Sequential | No parallelization |
monoidal |
Parallel | Fully parallelizable |
trace |
Iterative | Fixed-point iteration overhead |
Optimization Tips:
- Prefer monoidal for independent operations (enables GPU parallelization)
- Minimize trace depth (each trace adds iteration overhead)
- Factor out trace:
trace(composition(f, g))may be slower than alternatives
Equation-Level Operations
The following operations are available in the equation grammar but do not have direct circuit atomic equivalents. They are handled during compilation via rewrite rules.
sqrt(term)
Description: Square root of a term. Used in equations such as the chemical Langevin equation.
Syntax:
eq = Equation.from_string("sqrt(x)")
Compiles to: power(0.5) circuit atomic during equation-to-circuit translation.
Example:
# Chemical Langevin equation diffusion term
eq = Equation.from_string("sqrt(N)")
Complete Examples
Example 1: Polynomial Differentiation
# Differentiate f(x) = x³ + 2x² + 3x + 4
# Coefficients: [4, 3, 2, 1]
# Expected: f'(x) = 3x² + 4x + 3
circuit = Circuit.from_string("deregister(x)")
input_stream = Stream(
data=jnp.array([[4.0, 3.0, 2.0, 1.0]]),
dim_labels=("x",),
chunk_size=1
)
outputs, state = circuit.execute([input_stream], StreamState())
print(outputs[0].data) # [3.0, 4.0, 3.0]
Example 2: Arithmetic Pipeline
# Circuit: 2x + 3
circuit = Circuit.from_string(
"composition(monoidal(scalar(2.0), const(3.0)), add)"
)
input_stream = Stream(data=jnp.array([[5.0]]), dim_labels=(), chunk_size=1)
outputs, state = circuit.execute([input_stream], StreamState())
# Output: 2.0 * 5.0 + 3.0 = 13.0
Example 3: Solving dy/dt = -y
# Differential equation: dy/dt = -y
# Integral form: y = y₀ - ∫y dt
# Use trace for feedback
circuit = Circuit.from_string(
"trace(composition("
" monoidal(id, composition(scalar(-1.0), register(t))),"
" add"
"))"
)
Next Steps
- Equation Grammar - Equation syntax
- Circuit Grammar - Circuit syntax
- Circuits Concepts - Using circuits