Structures
All structures are immutable, frame-annotated, and built on plain
jax.numpy arrays internally — every method returns a symbolic
Expr, so distances, areas, and interpolated
values compose with the rest of the graph and stay differentiable. A
singular form (Point, Line) is simply a batch-of-one of the plural
form (PointList, LineList), sharing the same API.
Point / PointList
- class prophys.structures.PointList(coords, frame, registry=None)[source]
An immutable collection of n points in frame, shape
(n, ndim).Coordinates may be a plain array (fixed data, e.g. house locations) or an Expr (e.g. a Param, so the points themselves are optimizable — e.g. turbine positions).
- Parameters:
coords (Any)
frame (Frame)
- closest_distance(other, mode=None, tau=None)[source]
For each of self’s points, the distance to the closest point in other. Shape
(n,).Exact minimum (BVH-accelerated native kernel, O(n log m)) or a smooth softmin (temperature tau), chosen at evaluate time: pass mode=”eval”/”opt” explicitly to force a choice for this node specifically, or leave both None (the default) to follow whatever the model’s compile(mode=, tau=) selected.
- closest_point(other)[source]
For each of self’s points, the coordinates of the closest point in other. Shape
(n, ndim). Hard argmin (indexing is inherently discrete); use closest_distance in optimization objectives.
Line / LineList
- class prophys.structures.LineList(segments, frame, registry=None)[source]
A set of m straight segments in frame.
segments has shape
(m, 2, ndim)— start/end point per segment. Polylines can be represented by chaining consecutive segments.- Parameters:
segments (Any)
frame (Frame)
- closest_distance(points, mode=None, tau=None)[source]
Distance from each point to the closest segment. Shape
(n,).Native BVH-cached exact kernel (O(n log m)), or a smooth softmin over the dense distance matrix, chosen at evaluate time: pass mode=”eval”/”opt” explicitly to force a choice for this node, or leave both None (the default) to follow the model’s compile(mode=, tau=) setting.
Polyline
An ordered, connected vertex chain — a route — as opposed to
LineList’s unordered bag of independent segments. Its distinguishing
capability is point_at(): a
differentiable position at any fractional arc length along the whole
chain, gradient flowing to the route’s own vertex coordinates. This is
the primitive for “a failure can occur anywhere along this route” models
— a pipeline leak, a cable fault, a road-defect location — where the
failure location itself should be a continuous, reparameterized
RandomVariable rather than a hand-picked set of
candidate points:
import jax
import jax.numpy as jnp
import prophys as prp
site = prp.Frame("site", units="m")
route = prp.Polyline(prp.Param("route", shape=(4, 2), init=initial_vertices), site)
def expected_exposure(leak_key, receivers, wind_speed, wind_direction):
leak_point = route.point_at(jax.random.uniform(leak_key, ()))
# ... a plume/dispersion surrogate from leak_point to receivers,
# exactly as in the gas-dispersion example, marginalized over the
# wind climatology and now also over the leak's own location.
Design optimization can then move the route’s vertices — via
prp.optimize — to jointly minimize expected exposure and routing
cost, with the uncertainty over where a leak occurs built into the
objective rather than assumed away.
- class prophys.structures.Polyline(vertices, frame, registry=None)[source]
An ordered chain of v vertices in frame,
(v, ndim).vertices may be a Param (so the route itself is optimizable, e.g. a pipeline’s siting). Unlike LineList (an unordered bag of m independent segments), a Polyline is a single connected route: consecutive vertices are joined into segments, and point_at gives a differentiable position anywhere along the whole chain, parameterized by fractional arc length rather than a discrete segment index.
- Parameters:
vertices (Any)
frame (Frame)
- point_at(t)[source]
Differentiable position at fractional arc-length t (any shape, clamped to
[0, 1]) along the route. Shape(*t.shape, ndim). Differentiable in both the route’s vertex coordinates and t itself — the key primitive for treating “where along the route” as a continuous, reparameterized RandomVariable (Uniform(0, 1)pushed through point_at) rather than a hand-picked discrete set of candidate locations.
- as_lines()[source]
The route’s consecutive vertex pairs as a LineList of segments
(v - 1, 2, ndim), so every segment primitive (closest_distance, distance_matrix, …) works directly on the route geometry — e.g. distance from a receptor to the nearest point on the pipeline.- Return type:
Ray / RayList
A half-infinite line {origin + t * direction : t >= 0} — line-of-sight,
sensor exposure, and directional risk (e.g. distance to the nearest hazard
along a fixed bearing).
- class prophys.structures.RayList(origins, directions, frame, registry=None)[source]
A set of m rays in frame. origins has shape
(m, d), directions has shape(m, d)(need not be normalized).- Parameters:
origins (Any)
directions (Any)
frame (Frame)
- closest_distance(points, mode=None, tau=None)[source]
Distance from each point to the closest ray. Shape
(n,).Hard min or smooth softmin over the dense distance matrix, chosen at evaluate time: pass mode=”eval”/”opt” explicitly to force a choice for this node, or leave both None (the default) to follow the model’s compile(mode=, tau=) setting.
Ellipse / EllipseList
A rotatable ellipse. Signed distance is an approximation (there is no closed form for a general ellipse) — exact for a circle, and accurate enough for containment checks and optimization elsewhere.
- class prophys.structures.Ellipse(center, semi_axes, frame, angle=0.0, registry=None)[source]
A single ellipse in frame.
center has shape
(2,), semi_axes has shape(2,)=(a, b), angle is the rotation in radians (0 = major axis along the frame’s x-axis ifa >= b). All three may be Expr (e.g. Param), so an ellipse’s shape and pose can be learned or optimized.- Parameters:
center (Any)
semi_axes (Any)
frame (Frame)
angle (Any)
- signed_distance(points)[source]
Exact signed distance per point: negative inside, positive outside. Shape
(n,).
- contains(points, tau=None)[source]
Boolean (hard) or smooth-in-[0,1] (soft) containment indicator, via
sigmoid(-signed_distance / tau). Pass an explicit tau (0 or negative means hard, positive means smooth with that temperature) to force a choice for this node, or leave tau=None (the default) to follow the model’s compile(mode=, tau=) setting.
- perimeter()[source]
Ramanujan’s second approximation for the ellipse perimeter — accurate to a few parts in 10^9 even for high eccentricity, and fully differentiable (no special functions required).
- Return type:
- point_at(t)[source]
Differentiable position on the boundary at parameter t (any shape), where
t=0/t=1are the point at angle 0 (before rotation, the+aend of the major/x semi-axis) and t advances counter-clockwise around the full ellipse as it goes from 0 to 1. Shape(*t.shape, 2). Closed form (no native kernel needed):center + R(angle) @ diag(a, b) @ (cos(2*pi*t), sin(2*pi*t)).Note this is an angle parameterization, not an arc-length one (Polyline/Polygon.point_at’s convention): an ellipse’s arc length has no closed form in terms of its parametric angle (it’s an elliptic integral), so equal steps in t are not equal steps in boundary distance unless
a == b. For “a fault can occur anywhere on this ring, weighted by physical distance” use cases where uniform-arc-length sampling matters, approximate the ellipse with a Polygon instead and use its arc-length point_at.
- class prophys.structures.EllipseList(centers, semi_axes, angles, frame, registry=None)[source]
A collection of k ellipses. centers has shape
(k, 2), semi_axes has shape(k, 2), angles has shape(k,).- Parameters:
centers (Any)
semi_axes (Any)
angles (Any)
frame (Frame)
- signed_distance(points)[source]
Shape
(n, k): exact signed distance from each point to each ellipse, vmap-batched over the native single-ellipse kernel.
Polygon / PolygonList
- class prophys.structures.Polygon(vertices, frame, registry=None)[source]
A single closed polygon (no holes) in frame.
vertices has shape
(v, 2); the ring is implicitly closed (last vertex connects back to the first).- Parameters:
vertices (Any)
frame (Frame)
- signed_distance(points)[source]
Signed distance per point: negative inside, positive outside. Shape
(n,). Native kernel: BVH nearest edge + crossing-number sign, O(n log v).
- contains(points, tau=None)[source]
Boolean (hard) or smooth-in-[0,1] (soft) containment indicator, via
sigmoid(-signed_distance / tau). Pass an explicit tau (0 or negative means hard, positive means smooth with that temperature) to force a choice for this node, or leave tau=None (the default) to follow the model’s compile(mode=, tau=) setting.
- point_at(t)[source]
Differentiable position at fractional arc-length t (any shape, clamped to
[0, 1]) around the closed perimeter — the same arc-length parameterization as Polyline.point_at, with the ring wrapping from the last vertex back to the first. Shape(*t.shape, 2). Differentiable in both the polygon’s vertex coordinates and t.
- class prophys.structures.PolygonList(vertices, frame, registry=None)[source]
A collection of k polygons, each with the same vertex count v (pad/repeat vertices for irregular polygons). vertices has shape
(k, v, 2).- Parameters:
vertices (Any)
frame (Frame)
Polyhedron / PolyhedronList
3D convex bodies given by a halfspace representation \(\{x : Ax \le b\}\). Used, e.g., for underground storage-tank exclusion volumes.
- class prophys.structures.Polyhedron(A, b, frame, registry=None)[source]
A single convex polyhedron given by halfspaces
A x <= b.A has shape
(m, 3), b has shape(m,).- Parameters:
A (Any)
b (Any)
frame (Frame)
- signed_distance(points, mode=None, tau=None)[source]
Signed distance per point (negative inside). The “opt” branch uses a smooth softmax combination over faces with temperature tau; pass mode=”eval”/”opt” explicitly to force a choice for this node, or leave both None (the default) to follow the model’s compile(mode=, tau=) setting.
- contains(points, tau=None)[source]
Boolean (hard) or smooth-in-[0,1] containment indicator, via
sigmoid(-signed_distance / tau). Pass an explicit tau (0 or negative means hard, positive means smooth with that temperature) to force a choice for this node, or leave tau=None (the default) to follow the model’s compile(mode=, tau=) setting — which also then drives the underlying signed_distance the same way.
- volume(samples=20000, key=None)[source]
Monte-Carlo volume estimate within the polyhedron’s bounding box.
Convex-hull-exact volume needs a triangulation; for a general halfspace polyhedron we estimate via sampling (native kernel, sigmoid-smoothed containment indicator), which stays differentiable w.r.t. A/b. Caller is expected to pre-scale coordinates so a unit cube around the origin contains the shape for this estimator.
Field
A raster (scalar or vector) defined on a regular grid in a frame, with
differentiable bilinear interpolation at arbitrary query points via
jax.scipy.ndimage.map_coordinates.
- class prophys.structures.Field(values, frame, origin=(0.0, 0.0), cell=1.0, registry=None)[source]
A raster defined on a regular grid in frame.
values has shape
(ny, nx)for a scalar field or(ny, nx, c)for a vector field (e.g. windu, vcomponents withc=2). origin is the world coordinate of cell(0, 0); cell is the cell size (scalar or(dy, dx)); rows advance along the frame’s second axis (y), columns along the first (x), matching image-array convention.- Parameters:
- interp(points)[source]
Bilinearly interpolate the field at points. Shape
(n,)for scalar fields,(n, c)for vector fields. The native kernel fuses the world-to-index transform with the interpolation.
Grid
A fixed rectangular candidate domain — not itself part of the probabilistic model, but the standard way to evaluate an expression densely for a risk-map plot or a design search.
- class prophys.structures.Grid(frame, x_range, y_range, nx, ny)[source]
A regular grid of candidate points in frame.
Not itself an Expr (it’s a fixed geometric domain, not part of the probabilistic model), but .positions() returns a PointList that can be fed into any structure/primitive.
- Parameters:
Network
A directed graph in a shared frame: nodes are a PointList
(coordinates may be a Param, so siting is optimizable), edges are a
fixed (m, 2) connectivity array, and each edge carries an optional
transmission weight — any expression, commonly a
BinaryState when whether a link is reinforced,
open, or online is itself a design decision. Network models supply
chains, power grids, and pipeline networks where risk cascades along
edges: edge_lengths() gives per-edge
distances (cable/pipe cost), as_lines()
exposes the edges as a LineList for
proximity queries (e.g. distance from a house to the nearest line), and
propagate() runs a differentiable
multi-hop cascade of a per-node signal (a fault, a contamination front, a
load spike) along the directed edges, decaying or amplifying at each hop
according to the edge weights.
- class prophys.structures.Network(nodes, edges, frame, weights=None, registry=None)[source]
A directed graph in frame.
nodes is a PointList (or raw
(n, ndim)coordinates — which may be a Param, so node positions are optimizable); edges is a fixed(m, 2)integer array of (src, dst) node indices — connectivity is structure, not a differentiable quantity; weights is an optional(m,)per-edge transmission factor (any Expr, e.g. a Param or a vector of BinaryState`s stacked with :func:`prophys.stack), defaulting to 1 on every edge.Evaluating a Network yields its node coordinates, so it nests inside other expressions like a PointList does.
- Parameters:
nodes (Any)
edges (Any)
frame (Frame)
weights (Any)
- edge_lengths()[source]
Euclidean length of each edge, shape
(m,)— differentiable in the node coordinates.- Return type:
- as_lines()[source]
The edges as a LineList of segments
(m, 2, ndim), so every segment primitive (closest_distance, distance_matrix, …) works on the network geometry — e.g. distance from houses to the nearest power line.- Return type:
- propagate(source, steps=1, weights=None)[source]
Cascade a per-node signal source (shape
(n,)) along the directed edges for steps hops and return the accumulated per-node signalsum_{k<=steps} (M_w)^k source, shape(n,).Each hop multiplies by the per-edge transmission weight, so a failure/load/contamination signal decays (w < 1) or amplifies (w > 1) as it travels. Differentiable in both source and the weights — with BinaryState weights the cascade topology itself becomes a design variable.
Field3D / Grid3
The volumetric counterparts of Field/Grid: a voxel raster on a
regular 3D grid with differentiable trilinear interpolation, and a dense
3D evaluation lattice. Used for subsurface property fields, 3D
concentration plumes, and atmospheric or thermal gradients where a single
2D slice isn’t enough.
- class prophys.structures.Field3D(values, frame, origin=(0.0, 0.0, 0.0), cell=1.0, registry=None)[source]
A voxel raster on a regular 3D grid in frame.
values has shape
(nz, ny, nx)for a scalar field or(nz, ny, nx, c)for a vector field (e.g. a 3D flow withc=3). origin is the world coordinate(x, y, z)of voxel(0, 0, 0); cell is the voxel size (scalar or(dx, dy, dz)). Axis convention matches Field: the last array axis is x, then y, then z.- Parameters:
Mesh
An unstructured triangular mesh carrying a per-vertex scalar field, with
differentiable barycentric (P1 finite-element) interpolation — the
ingestion point for FEM/CFD solver outputs (stress, pressure,
concentration) into a prophys graph. The mesh connectivity and vertex
positions are fixed structure; the field values (and query points) stay
differentiable, so a mesh-sampled physics surrogate can be calibrated
against observations exactly like any other attribute.
- class prophys.structures.Mesh(vertices, triangles, values, frame, registry=None)[source]
A fixed triangulation in frame with a per-vertex field.
vertices is a fixed
(v, 2)coordinate array and triangles a fixed(t, 3)integer connectivity array — the mesh is structure. values is the(v,)per-vertex field and may be any Expr (a Param makes the field itself calibratable against point observations). Interpolation is piecewise linear (the FEM P1 basis): exact at vertices, linear inside each triangle, and linearly extrapolated from the nearest triangle outside the mesh so gradients stay defined everywhere.- Parameters:
vertices (Any)
triangles (Any)
values (Any)
frame (Frame)