Differential Operators
jno.numpy (importable as jnn) is a drop-in NumPy-compatible module that operates on symbolic Placeholder expressions. It provides automatic and finite-difference differential operators for formulating PDE residuals, plus the full NumPy math library for use inside constraints.
Differentiation
Gradient (first derivative)
# ∂u/∂x — automatic differentiation (default)
u_x = jnn.grad(u, x)
# ∂u/∂x — mesh-based finite differences
u_x = jnn.grad(u, x, scheme="finite_difference")
jnn.grad returns a Jacobian placeholder.
Laplacian
# ∇²u = ∂²u/∂x² + ∂²u/∂y² — automatic differentiation (default)
lap = jnn.laplacian(u, [x, y])
# Finite-difference Laplacian (uses mesh connectivity — requires compute_mesh_connectivity=True)
lap = jnn.laplacian(u, [x, y], scheme="finite_difference")
jnn.laplace is an alias for jnn.laplacian.
Jacobian (vector-valued)
Hessian matrix
Divergence
Curl
# 2D curl (scalar): ∂Fy/∂x − ∂Fx/∂y
curl = jnn.curl_2d(Fx, Fy, x, y)
# 3D curl (vector): [∂Fz/∂y−∂Fy/∂z, ∂Fx/∂z−∂Fz/∂x, ∂Fy/∂x−∂Fx/∂y]
curl_vec = jnn.curl_3d(Fx, Fy, Fz, x, y, z)
Differentiation Schemes
| Scheme | Flag | Notes |
|---|---|---|
| Automatic Differentiation | "automatic_differentiation" (default) |
Exact; uses JAX jax.grad / jax.jacfwd. |
| Finite Difference (mesh-based) | "finite_difference" |
Approximation; uses FEM stencils. Requires compute_mesh_connectivity=True in the domain. |
Mathematical Functions
Trigonometric
jnn.sin(x), jnn.cos(x), jnn.tan(x)
jnn.arcsin(x), jnn.arccos(x), jnn.arctan(x)
jnn.arctan2(y, x) # alias: jnn.atan2
Hyperbolic
Exponential / Logarithm
Power / Root
Absolute / Rounding
Constants
Reduction Operations
jnn.sum(x)
jnn.mean(x)
jnn.std(x)
jnn.var(x)
jnn.min(x)
jnn.max(x)
jnn.median(x)
jnn.prod(x)
jnn.norm(x, ord=None, axis=None)
All support axis= and keepdims= keyword arguments.
Reduction Properties on Placeholders
Every Placeholder expression exposes reduction properties. These return scalar Placeholder nodes suitable for use as constraints or trackers:
expr.mse # mean(expr²) — most common loss term
expr.mae # mean(|expr|)
expr.mean # mean(expr)
expr.sum # sum(expr)
expr.max # max(expr)
expr.min # min(expr)
expr.std # std(expr)
Example:
Array Operations
jnn.concat([x, y], axis=-1) # concatenate along last axis (default)
jnn.concatenate([x, y]) # alias for concat
jnn.stack([x, y], axis=0) # stack along new axis
jnn.reshape(x, shape)
jnn.squeeze(x, axis=None)
jnn.expand_dims(x, axis)
jnn.transpose(x, axes=None)
Comparison / Conditional
Comparison operators are also available as methods on Placeholder objects:
x > 0.5 # FunctionCall(greater, [x, Literal(0.5)])
x.equal(y) # element-wise equality (traced)
x.not_equal(y)
Linear Algebra
jnn.dot(x, y)
jnn.matmul(x, y)
jnn.cross(x, y)
# Matrix multiply on Placeholder: x @ A
result = x @ A
View Factor Operator (Radiation)
For radiation boundary conditions the domain can compute a view-factor matrix. Use jnn.view_factor to create an operator that applies it symbolically:
# Get view factor matrix from domain
xb, yb, tb, nx, ny, VF = domain.variable("boundary", normals=True, view_factor=True)
# Wrap as a symbolic linear operator
VF_op = jnn.view_factor(VF)
# Apply: radiative heat flux received by each boundary point
q_inc = VF_op @ q_emitted # F @ q (matrix-vector product)
q_inc = q_emitted @ VF_op # q @ F
# Solve (I - αF)x = rhs
x = VF_op.solve(rhs, alpha)
Custom Functions
Wrap arbitrary JAX functions for use inside symbolic expressions:
Symbolic Arithmetic
Placeholders support standard Python arithmetic, enabling natural PDE notation:
u = u_net(x, y)
v = v_net(x, y)
# Arithmetic
w = u + v
w = u * 2.0
w = u ** 2
w = -u
# Matrix multiplication
w = A @ u
Trackers
Mark an expression as a tracked metric — it is evaluated and logged during training but does not contribute to the loss:
from jno.numpy import tracker
val_error = tracker(jnn.mean(u(x, y) - u_exact(x, y)), interval=100) # log every 100 epochs
crux = jno.core([pde.mse, boc.mse, val_error], domain)
Constants Namespace
Load constant values from a file or dict and use them symbolically in expressions:
C = jnn.constant("C", {
"k": 1.5,
"rho": 2700,
"cp": 900,
"physics": {"g": 9.81, "nu": 1.5e-5},
})
# Use in constraints
pde = -C.k * jnn.laplacian(u, [x, y]) - C.rho * jnn.grad(u, t)
# Load from file
C = jnn.constant("C", "params.json") # JSON
C = jnn.constant("C", "params.yaml") # YAML
C = jnn.constant("C", "params.toml") # TOML
C = jnn.constant("C", "data.npz") # NumPy npz