Examples

Working examples demonstrating Asgard's capabilities for deterministic and stochastic computation.

Deterministic Examples

Basic Integration

Integrate polynomial functions using the register operation.

Fundamental Theorem

Verify that differentiation and integration are inverses.

Taylor Series

Evaluate polynomial expansions at specific points.

Example 1: Basic Integration

Integrate f(x) = x to get x^2/2:

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

# Create integration circuit
circuit = Circuit.from_string("register(x)")

# Input: f(x) = x (Taylor 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]}")   # [0. 1.] = x
print(f"Output: {outputs[0].data[0]}")    # [0. 0. 1.] = x^2/2

Example 2: Fundamental Theorem of Calculus

Verify that d/dx(integral f dx) = f:

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

# d/dx(integral f dx) = composition of register then deregister
circuit = Circuit.from_string("composition(register(x), deregister(x))")

# Input coefficients
input_stream = Stream(
    data=jnp.array([[1.0, 2.0, 3.0, 4.0, 5.0]]),
    dim_labels=("x",),
    chunk_size=1
)

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

print(f"Input:  {input_stream.data[0]}")   # [1. 2. 3. 4. 5.]
print(f"Output: {outputs[0].data[0]}")     # [1. 2. 3. 4.] (recovers original)

Example 3: Taylor Series Evaluation

Evaluate a polynomial at specific points using RealCalculus:

from gimle.asgard.runtime.stream import Stream
from gimle.asgard.runtime.stream_evaluator import StreamEvaluator, RealCalculus
import jax.numpy as jnp

# Coefficients for f(x) = 2 + 3x + x^2/2
stream = Stream(
    data=jnp.array([[2.0, 3.0, 1.0]]),
    dim_labels=("x",),
    chunk_size=1
)

# Create evaluator
evaluator = StreamEvaluator(stream, {"x": RealCalculus(center=0.0)})

# Evaluate at 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 = 2.0 + 3.0*x + 1.0*(x**2)/2.0
    print(f"f({x:.1f}) = {val:.2f} (expected: {expected:.2f})")

Example 4: Equation to Circuit

Compile an equation to an executable circuit:

from gimle.asgard.equation.equation import Equation
from gimle.asgard.compile.compiler import compile_equation_to_circuit
from gimle.asgard.runtime.stream import Stream, StreamState
import jax.numpy as jnp

# Define equation
eq = Equation.from_string("diff(int(f, x), x) = f")

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

print(f"Circuit: {circuit}")
# Output: composition(register(x), deregister(x)) [1->1]

# Execute
input_stream = Stream(
    data=jnp.array([[1.0, 2.0, 3.0]]),
    dim_labels=("x",),
    chunk_size=1
)
outputs, state = circuit.execute([input_stream], StreamState())

Stochastic Examples

Brownian Motion

Generate sample paths of standard Brownian motion.

Ornstein-Uhlenbeck

Mean-reverting stochastic process simulation.

Black-Scholes

Monte Carlo option pricing using geometric Brownian motion.

Example 5: Brownian Motion

Generate Brownian motion paths:

from gimle.asgard.runtime.stream_evaluator import StochasticCalculus
import jax.numpy as jnp

# Create stochastic calculus
calculus = StochasticCalculus(
    drift=0.0,
    diffusion=1.0,
    n_paths=1000,
    dt=0.01,
    seed=42
)

# Generate Brownian motion paths
paths = calculus.generate_brownian_paths(t_start=0.0, t_end=2.0, n_steps=200)

# Verify statistical properties
print(f"Mean at t=2: {jnp.mean(paths[:, -1]):.3f}")     # ~ 0
print(f"Variance at t=2: {jnp.var(paths[:, -1]):.3f}")  # ~ 2

Example 6: Ornstein-Uhlenbeck Process

Simulate a mean-reverting process dX = -theta(X - mu)dt + sigma dW:

from gimle.asgard.runtime.stream_evaluator import StochasticCalculus
import jax.numpy as jnp

# Parameters
theta = 0.5   # Mean reversion speed
mu = 1.0      # Long-term mean
sigma = 0.3   # Volatility
x0 = 2.0      # Initial value

# Simulate
calculus = StochasticCalculus(n_paths=10000, dt=0.01)
paths = calculus.simulate_sde(
    x0=x0,
    drift_fn=lambda x, t: -theta * (x - mu),
    diffusion_fn=lambda x, t: sigma,
    t_start=0.0,
    t_end=5.0,
    n_steps=500
)

# Check convergence to equilibrium
print(f"Mean at t=5: {jnp.mean(paths[:, -1]):.3f}")  # Should approach mu=1.0

Example 7: Black-Scholes Option Pricing

Price a European call option using Monte Carlo:

from gimle.asgard.runtime.stream_evaluator import StochasticCalculus
import jax.numpy as jnp

# Stock parameters
S0 = 100.0     # Initial stock price
mu = 0.05      # Expected return
sigma = 0.2    # Volatility
T = 1.0        # Time to expiry

# Simulate geometric Brownian motion
calculus = StochasticCalculus(n_paths=100000, dt=0.001, seed=123)
paths = calculus.simulate_sde(
    x0=S0,
    drift_fn=lambda x, t: mu * x,
    diffusion_fn=lambda x, t: sigma * x,
    t_start=0.0,
    t_end=T,
    n_steps=1000
)

# Price European call option
K = 100.0  # Strike price
payoffs = jnp.maximum(paths[:, -1] - K, 0)
option_price = jnp.mean(payoffs) * jnp.exp(-mu * T)

print(f"Option price: ${option_price:.2f}")

Example 8: Parallel Operations

Apply different operations to multiple inputs:

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

# Apply 2x to first input, 3y to second input
circuit = Circuit.from_string("monoidal(scalar(2.0), scalar(3.0))")

print(f"Input degree: {circuit.input_degree}")    # 2
print(f"Output degree: {circuit.output_degree}")  # 2

# Two inputs
input1 = Stream(data=jnp.array([[5.0]]), dim_labels=(), chunk_size=1)
input2 = Stream(data=jnp.array([[4.0]]), dim_labels=(), chunk_size=1)

outputs, state = circuit.execute([input1, input2], StreamState())

print(f"Output 1: {outputs[0].data[0, 0]}")  # 10.0 (2 * 5)
print(f"Output 2: {outputs[1].data[0, 0]}")  # 12.0 (3 * 4)

Example 9: Stateful Processing

Process multiple chunks with preserved state:

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

circuit = Circuit.from_string("register(x)")

# Process first chunk
chunk1 = Stream(data=jnp.array([[1.0, 2.0, 3.0]]), dim_labels=("x",), chunk_size=1)
result1, state1 = circuit.execute([chunk1], StreamState())

print(f"Chunk 1 output: {result1[0].data[0]}")  # [0. 1. 2.]

# Process second chunk using state from first
chunk2 = Stream(data=jnp.array([[4.0, 5.0, 6.0]]), dim_labels=("x",), chunk_size=1)
result2, state2 = circuit.execute([chunk2], state1)

print(f"Chunk 2 output: {result2[0].data[0]}")  # [3. 4. 5.]

YAML Examples

In addition to the Python examples above, Asgard supports declarative YAML examples that can be run from the command line without writing any Python code:

# List all available YAML examples
uv run asgard example --list

# Run a single example
uv run asgard example basic/01_integration.yaml

# Run all examples in a category
uv run asgard example -c stochastic

# Run with the monitor dashboard
uv run asgard example -c basic --monitor

YAML examples cover deterministic, stochastic, discrete, optimization, and engineering categories. See the YAML Examples Guide for the complete field reference and how to write your own.

Next Steps