Tesseract¶
Universal components for differentiable scientific computing
Optimize, calibrate, and train through solvers in any language or framework
Tesseract wraps any software behind a typed interface with derivative endpoints, runs it in its own process, and hands it to jax.grad or torch.autograd as a single differentiable operation.
Open source, published in JOSS.
Why Tesseract¶
Tesseract is for differentiable programs that need to reach outside their own framework: solver-in-the-loop training, calibration and inverse problems, simulation-based inference, and shape optimization through real engineering tools.
Get validated legacy codes, commercial CAD and FEA, and closed-source binaries to play well alongside modern differentiable components.
Fortran, Julia, or C++ code becomes an operation that jax.grad and torch.autograd differentiate like native code.
Test every derivative against finite differences before an optimizer relies on it.
Each component runs in its own process, with its own dependencies. Shared memory and GPU-native transport keep calls cheap.
Combine adjoints, forward- and reverse-mode autodiff, and finite differences in one end-to-end gradient.
OpenAPI schemas and API docs are auto-generated from your code, and tesseract build takes it to other machines as a container image.
How it works¶
Define a differentiable component in tesseract_api.py, run it in its own process,
and call it, including its gradients, from Python, JAX, or PyTorch.
To run it on another machine, package the same file as a container image.
Define a Tesseract
# tesseract_api.py
from pydantic import BaseModel
from tesseract_core.runtime import (
Array, Differentiable, Float32, ShapeDType
)
class InputSchema(BaseModel):
x: Differentiable[Array[(None,), Float32]]
class OutputSchema(BaseModel):
y: Differentiable[Array[(None,), Float32]]
def apply(inputs: InputSchema) -> OutputSchema:
# Call your solver, mesh generator,
# or surrogate here
return OutputSchema(y=inputs.x**2)
def vector_jacobian_product(
inputs, vjp_inputs, vjp_outputs, cotangent_vector
):
# Hand-written, autodiff, adjoint solve,
# finite differences, ...
return {"x": 2 * inputs.x * cotangent_vector["y"]}
def abstract_eval(abstract_inputs):
# Output shapes from input shapes
return {"y": ShapeDType(
shape=abstract_inputs.x.shape, dtype="float32"
)}
Use it
from tesseract_core import Tesseract
with Tesseract.from_source("tesseract_api.py") as t:
result = t.apply({"x": [3.0]})
# result["y"] => array([9.])
vjp = t.vector_jacobian_product(
{"x": [3.0]},
vjp_inputs=["x"], vjp_outputs=["y"],
cotangent_vector={"y": [1.0]},
)
# vjp["x"] => array([6.])
import jax
import jax.numpy as jnp
from tesseract_core import Tesseract
from tesseract_jax import apply_tesseract
with Tesseract.from_source("tesseract_api.py") as t:
f = lambda x: apply_tesseract(t, {"x": x})["y"].sum()
jax.jit(f)(jnp.array([3.0]))
# => Array(9.)
jax.grad(f)(jnp.array([3.0]))
# => [6.]
import torch
from tesseract_core import Tesseract
from tesseract_torch import apply_tesseract
with Tesseract.from_source("tesseract_api.py") as t:
x = torch.tensor([3.0], requires_grad=True)
out = apply_tesseract(t, {"x": x})
# out["y"] => tensor([9.])
out["y"].sum().backward()
# x.grad => tensor([6.]) (via the VJP endpoint)
# Compare the VJP against finite differences
$ TESSERACT_API_PATH=tesseract_api.py \
tesseract-runtime check-gradients \
'{"inputs": {"x": [1.0, 2.0, 3.0]}}'
✅ Gradient check for vector_jacobian_product passed ✅
# Build a container image (requires Docker)
$ tesseract build .
$ tesseract run my-tesseract apply \
'{"inputs": {"x": [3.0]}}'
Built with Tesseract¶
A Julia semiconductor solver and a FEniCS optics solver in one JAX gradient, reaching more than five times the optical phase shift of the starting design.
A PyTorch network learns to calibrate NOAA’s operational Fortran models, Snow-17 and SAC-SMA, with gradients flowing through the untouched Fortran.
Ansys SpaceClaim geometry and PyMAPDL structural analysis in one optimization loop, giving a design 24% stiffer than the baseline at the same mass.
Sentaurus TCAD, a closed-source binary driven over SSH, differentiated with finite differences and Broyden updates to tune a transistor for a spiking network.
A PyTorch network proposes EEG sources, and JAX refines them with gradients through OpenMEEG, a C++ boundary element solver with no autodiff of its own.
Solvers in C++, Julia, JAX, and PyTorch, from deal.II and OpenFOAM to JAX-FEM and XLB, behind one Tesseract interface, so a single harness can compare their gradients and cost on shared tasks.
The Tesseract ecosystem¶
Tesseract Core is the foundation. Additional packages extend its capabilities.
CLI, Python SDK, and runtime for wrapping differentiable components and running them as subprocesses, containers, or remote services.
Embed Tesseracts as JAX primitives. Fully compatible with jit, vmap,
and grad.
Embed Tesseracts as PyTorch operators. Gradients flow through with
torch.autograd.
Also see Tesseract-Streamlit to generate web apps from Tesseracts, and cookiecutter-tesseract for a multi-Tesseract project template.
Get involved¶
Wrap your solver or model as a Tesseract, or compose existing ones into a new pipeline. Show us what you built, or help improve the project.