Runnable API examples¶
Start with ordinary torch.Tensor inputs and PyTorch gradients. Each recipe runs independently; assertions specify results and no variables are borrowed from other sections. The later native-runtime recipes are advanced compiler/storage examples, not a prerequisite for MessagePassing. See getting started for installation. Documentation tests execute these recipes, not just syntax-check them.
| Task | Contract | Complete example |
|---|---|---|
| Default Torch input/output and gradients | Torch-facing contract | Torch recipe |
| Tensor, views, gradients | Default Torch interface | Tensor recipe |
| CSR aggregation | Graph / MessagePassing | Message passing |
| Budgets, spill, persistence | Execution and storage | Storage |
| Physical transfers | Compiler memory | Physical instances |
| Backend selection and failures | Execution guide | Diagnostic code |
| IR and generated code | IR walkthrough | Stage artifacts |
| Reducers and semantics | Reducers | Graph algorithms |
| Torch / NN interop | Interop | Attention |
| Loops and implicit VJP | Solvers | Solver examples |
| Multiple processes and paged graphs | Support status | Distributed examples |
Default: Torch inputs, outputs and gradients¶
Install Torch separately before Tiga for this recipe; no CUDA or tg.from_torch
wrapper is needed. Native storage/runtime recipes do not require Torch.
import torch
import tiga as tg
class WeightedSum(tg.MessagePassing):
reducer = tg.sum()
def edge(self, src, dst, edge):
return src.x * edge.w
graph = tg.Graph.from_csr(torch.tensor([0, 2, 3, 3]),
torch.tensor([0, 1, 1]), num_src=2, validate="full")
x = torch.tensor([2., 3.], requires_grad=True)
w = torch.tensor([4., 5., 2.], requires_grad=True)
out = WeightedSum()(graph=graph, src={"x": x}, dst={}, edge={"w": w})
assert isinstance(out, torch.Tensor)
torch.testing.assert_close(out, torch.tensor([23., 6., 0.]))
dx, dw = torch.autograd.grad(out.sum(), (x, w))
torch.testing.assert_close(dx, torch.tensor([4., 7.]))
torch.testing.assert_close(dw, torch.tensor([2., 3., 3.]))
This validates the public value/gradient contract, not a claim that every provider uses generated code. Inspect the kernel's diagnostics for the selected execution route.
Torch Tensor, views and gradients¶
import torch
x = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)
view = x.transpose(0, 1)
loss = (view * view).sum()
dx, = torch.autograd.grad(loss, x)
assert loss.tolist() == 30.
assert dx.tolist() == [[2., 4.], [6., 8.]]
CSR message passing¶
import torch
import tiga as tg
class WeightedSum(tg.MessagePassing):
reducer = tg.sum()
def edge(self, src, dst, edge):
return src.x * edge.w
graph = tg.Graph.from_csr(torch.tensor([0, 2, 3], dtype=torch.int64),
torch.tensor([0, 1, 0], dtype=torch.int64), num_src=2)
x = torch.tensor([2., 3.], requires_grad=True)
w = torch.tensor([1., 2., 4.], requires_grad=True)
out = WeightedSum()(graph=graph, src={"x": x}, dst={}, edge={"w": w})
assert out.tolist() == [8., 8.]
assert torch.autograd.grad(out.sum(), x)[0].tolist() == [5., 2.]
Storage and allocation policy¶
from pathlib import Path
import tempfile
import tiga as tg
with tempfile.TemporaryDirectory(prefix="tiga-memory-example-") as directory:
with tg.execution(memory={"host": "1MiB", "nvme": "1MiB"},
spill_dir=directory) as run:
values = tg.tensor([float(i) for i in range(8)], requires_grad=True)
loss = (values * values).sum()
loss.spill() # temporary residency; autograd history survives
gradients = tg.autograd.grad(loss, values)
assert gradients.tolist() == [float(2 * i) for i in range(8)]
back = values.cpu()
path = Path(directory) / "activations.tiga"
tg.save(values, path) # persistent value snapshot, not an eviction
restored = tg.load(path) # metadata only until first observation
assert restored.tolist() == back.tolist()
print(run.memory_report())
Compiler physical-instance round trip¶
import tiga as tg
with tg.runtime.HierarchyRuntime(budgets={"ram": 8, "nvme": 4}) as rt:
source = rt.allocate("x", 0, tier="ram", capacity_bytes=4)
source.buffer.write(b"tiga")
page = rt.allocate("x", 0, tier="nvme", capacity_bytes=4)
rt.transfer(source, page).wait()
destination = rt.allocate("x", 0, tier="ram", capacity_bytes=4)
rt.transfer(page, destination).wait()
assert destination.buffer.read() == b"tiga"