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)

pairwise_distance(other)[source]

(n, m) matrix of Euclidean distances to other’s points.

Parameters:

other (PointList)

Return type:

Expr

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.

Parameters:
Return type:

Expr

farthest_distance(other, mode=None, tau=None)[source]
Parameters:
Return type:

Expr

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.

Parameters:

other (PointList)

Return type:

Expr

farthest_point(other)[source]
Parameters:

other (PointList)

Return type:

Expr

average_distance(other)[source]
Parameters:

other (PointList)

Return type:

Expr

count_within(other, radius, mode=None, tau=None)[source]

For each of self’s points, how many of other’s points lie within radius. Sigmoid-smoothed indicator in the “opt” branch; mode/tau follow compile()’s setting when left None (see closest_distance for the full explanation).

Parameters:
Return type:

Expr

centroid()[source]
Return type:

Expr

class prophys.structures.Point(coords, frame, registry=None)[source]

A single point — a PointList of length 1 with the same API.

Parameters:
  • coords (Any)

  • frame (Frame)

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)

distance_matrix(points)[source]

(n, m) distances from each point to each segment.

Parameters:

points (PointList)

Return type:

Expr

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.

Parameters:
Return type:

Expr

length()[source]

Total length of all segments (sum), shape ().

Return type:

Expr

class prophys.structures.Line(start, end, frame, registry=None)[source]

A single segment — a LineList of length 1 with the same API.

Parameters:
  • start (Any)

  • end (Any)

  • frame (Frame)

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.

Parameters:

t (Any)

Return type:

Expr

length()[source]

Total arc length of the route, shape ().

Return type:

Expr

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:

LineList

sample_points(key, shape=())[source]

Reparameterized draws of a uniformly random location along the route: u ~ Uniform(0, 1) pushed through point_at. Shape (*shape, ndim). Differentiable in the route’s vertex coordinates, exactly like any other distribution’s sample.

Parameters:
Return type:

Expr

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)

distance_matrix(points)[source]

(n, m) distances from each point to each ray.

Parameters:

points (PointList)

Return type:

Expr

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.

Parameters:
Return type:

Expr

point_at(t)[source]

Position along each ray at parameter t (shape broadcastable to (m,)): origin + t * unit_direction. Shape (m, d).

Parameters:

t (Any)

Return type:

Expr

class prophys.structures.Ray(origin, direction, frame, registry=None)[source]

A single ray — a RayList of length 1 with the same API.

Parameters:
  • origin (Any)

  • direction (Any)

  • frame (Frame)

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 if a >= 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,).

Parameters:

points (PointList)

Return type:

Expr

distance(points)[source]

Unsigned distance (0 if inside).

Parameters:

points (PointList)

Return type:

Expr

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.

Parameters:
Return type:

Expr

area()[source]
Return type:

Expr

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:

Expr

point_at(t)[source]

Differentiable position on the boundary at parameter t (any shape), where t=0/t=1 are the point at angle 0 (before rotation, the +a end 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.

Parameters:

t (Any)

Return type:

Expr

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.

Parameters:

points (PointList)

Return type:

Expr

closest_distance(points)[source]

Distance to the closest ellipse (hard min over k), shape (n,).

Parameters:

points (PointList)

Return type:

Expr

area()[source]

Total area of all k ellipses, shape (k,).

Return type:

Expr

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).

Parameters:

points (PointList)

Return type:

Expr

distance(points)[source]

Unsigned distance to the boundary/interior (0 if inside).

Parameters:

points (PointList)

Return type:

Expr

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.

Parameters:
Return type:

Expr

area()[source]
Return type:

Expr

perimeter()[source]
Return type:

Expr

centroid()[source]
Return type:

Expr

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.

Parameters:

t (Any)

Return type:

Expr

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)

signed_distance(points)[source]

Shape (n, k): signed distance from each point to each polygon. The native kernel batches over the polygon axis directly.

Parameters:

points (PointList)

Return type:

Expr

closest_distance(points)[source]

Distance to the closest polygon (hard min over k), shape (n,).

Parameters:

points (PointList)

Return type:

Expr

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.

Parameters:
Return type:

Expr

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.

Parameters:
Return type:

Expr

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.

Parameters:
Return type:

Expr

class prophys.structures.PolyhedronList(A, b, frame, registry=None)[source]

A collection of k convex polyhedra sharing the same face count m. A has shape (k, m, 3), b has shape (k, m).

Parameters:
  • A (Any)

  • b (Any)

  • frame (Frame)

closest_distance(points, tau=1.0)[source]

Distance from each point to the closest polyhedron. Shape (n,).

Parameters:
Return type:

Expr

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.

_images/gas_dispersion_terrain.png
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. wind u, v components with c=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.

Parameters:

points (PointList)

Return type:

Expr

gradient()[source]

Return a vector Field of finite-difference spatial gradients (d/dy, d/dx) of a scalar field, same shape grid, channel=2.

Return type:

Field

mean()[source]
Return type:

Expr

min(tau=0.0)[source]
Parameters:

tau (float)

Return type:

Expr

max(tau=0.0)[source]
Parameters:

tau (float)

Return type:

Expr

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.

_images/gas_dispersion_risk_map.png
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:
positions()[source]
Return type:

PointList

shape()[source]
Return type:

tuple[int, int]

mask(polygon)[source]

Boolean (ny, nx) mask of which grid cells fall inside polygon.

Return type:

Array

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)

property n_nodes: int
edge_lengths()[source]

Euclidean length of each edge, shape (m,) — differentiable in the node coordinates.

Return type:

Expr

total_length()[source]

Total edge length (e.g. cable/pipe cost), shape ().

Return type:

Expr

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:

LineList

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 signal sum_{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.

Parameters:
Return type:

Expr

in_strength(weights=None)[source]

Weighted in-degree of each node (one-hop received signal from a unit source everywhere), shape (n,).

Parameters:

weights (Any)

Return type:

Expr

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 with c=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:
interp(points)[source]

Trilinearly interpolate the field at points (a PointList of 3D coordinates). Shape (n,) for scalar fields, (n, c) for vector fields. The native kernel fuses the world-to-voxel transform with the interpolation.

Parameters:

points (PointList)

Return type:

Expr

mean()[source]
Return type:

Expr

min(tau=0.0)[source]
Parameters:

tau (float)

Return type:

Expr

max(tau=0.0)[source]
Parameters:

tau (float)

Return type:

Expr

class prophys.structures.Grid3(frame, x_range, y_range, z_range, nx, ny, nz)[source]

A regular 3D grid of evaluation positions in frame — the volumetric counterpart of Grid, for sampling a Field3D densely or defining a 3D design-candidate lattice. Not itself an Expr.

Parameters:
positions()[source]
Return type:

PointList

shape()[source]
Return type:

tuple[int, int, int]

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)

interp(points)[source]

Barycentric interpolation of the vertex field at points, shape (n,) — differentiable in the field values and the query points (constant per-triangle spatial gradient).

Parameters:

points (PointList)

Return type:

Expr

area()[source]

Total mesh area (fixed structure, a plain array not an Expr).

Return type:

Array

integral()[source]

Integral of the P1 field over the mesh (area-weighted mean of each triangle’s vertex values) — differentiable in the values.

Return type:

Expr