Getting Started

This guide will help you set up Asgard and create your first circuit.

Installation

1. Prerequisites

You need Python 3.10+ and either uv (recommended) or pip.

2. Install Asgard

With uv (recommended):

git clone https://github.com/arnovich/gimle-asgard.git
cd gimle-asgard
uv sync

With pip:

git clone https://github.com/arnovich/gimle-asgard.git
cd gimle-asgard
pip install -e .

3. Verify Installation

uv run python -c "from gimle.asgard.circuit.circuit import Circuit; print('Asgard installed!')"

Your First Circuit

Let's create a simple circuit that integrates a function.

Create a Circuit

from gimle.asgard.circuit.circuit import Circuit

# Create a circuit that performs integration along dimension x
circuit = Circuit.from_string("register(x)")

print(circuit)
# Output: register(x) [1->1]

Prepare Input Data

from gimle.asgard.runtime.stream import Stream, StreamState
import jax.numpy as jnp

# Coefficients for f(x) = x (polynomial [0, 1])
input_stream = Stream(
    data=jnp.array([[0.0, 1.0]]),
    dim_labels=("x",),
    chunk_size=1
)

Execute the Circuit

# Run the circuit
outputs, state = circuit.execute([input_stream], StreamState())

print(f"Output coefficients: {outputs[0].data}")
# Output: [[0. 0. 1.]]

Integration of x gives x^2/2, which has Taylor coefficients [0, 0, 1] (meaning 0 + 0x + 1x^2).

Evaluate the Result

from gimle.asgard.runtime.stream_evaluator import StreamEvaluator, RealCalculus

# Create evaluator with real (deterministic) calculus
evaluator = StreamEvaluator(outputs[0], {"x": RealCalculus()})

# Evaluate at specific points
x_points = jnp.array([0.0, 1.0, 2.0, 3.0])
values = evaluator.evaluate(x=x_points)

for x, val in zip(x_points, values):
    expected = x**2 / 2
    print(f"x={x:.1f}: {val:.2f} (expected: {expected:.2f})")

Your First Equation

Now let's start from an equation and compile it to a circuit.

Define an Equation

from gimle.asgard.equation.equation import Equation

# Fundamental theorem of calculus: d/dx(integral of f) = f
equation = Equation.from_string("diff(int(f, x), x) = f")

print(equation)
# Output: diff(int(f, x), x) = f

Compile to Circuit

from gimle.asgard.compile.compiler import compile_equation_to_circuit

# Compile equation to circuit (variable isolation is automatic)
circuit, metadata = compile_equation_to_circuit(equation)

print(circuit)
# Output: composition(register(x), deregister(x)) [1->1]

Test It

# Input: f(x) = x (coefficients [0, 1])
input_stream = Stream(
    data=jnp.array([[0.0, 1.0]]),
    dim_labels=("x",),
    chunk_size=1
)

# Execute
outputs, state = circuit.execute([input_stream], StreamState())

print(f"Input:  {input_stream.data[0]}")
print(f"Output: {outputs[0].data[0]}")
# Both should be [0, 1] - the fundamental theorem holds!

Common Patterns

Integration

# Integrate along dimension x
circuit = Circuit.from_string("register(x)")

Differentiation

# Differentiate along dimension t
circuit = Circuit.from_string("deregister(t)")

Arithmetic

# Add two inputs
circuit = Circuit.from_string("add")

# Multiply by constant
circuit = Circuit.from_string("scalar(5.0)")

# Chain operations: f -> 2f -> integrate(2f)
circuit = Circuit.from_string("composition(scalar(2.0), register(x))")

Parallel Operations

# Apply different scalars to two inputs
circuit = Circuit.from_string("monoidal(scalar(2.0), scalar(3.0))")

Quick Reference

Import Cheat Sheet

# Core classes
from gimle.asgard.equation.equation import Equation
from gimle.asgard.circuit.circuit import Circuit
from gimle.asgard.runtime.stream import Stream, StreamState
from gimle.asgard.runtime.stream_evaluator import StreamEvaluator, RealCalculus

# Compilation
from gimle.asgard.compile.compiler import compile_equation_to_circuit

# JAX
import jax.numpy as jnp

Common Workflows

Equation to Circuit to Execution:

eq = Equation.from_string("diff(f, x) = g")
circuit, metadata = compile_equation_to_circuit(eq)
outputs, state = circuit.execute(inputs, StreamState())

Circuit to Evaluation:

circuit = Circuit.from_string("register(x)")
outputs, state = circuit.execute([input_stream], StreamState())
evaluator = StreamEvaluator(outputs[0], {"x": RealCalculus()})
values = evaluator.evaluate(x=jnp.linspace(0, 10, 100))

Next Steps