/** * Halfspace intersection / vertex enumeration (2-D & 3-D) — completes the * computational-geometry engine. * * Given a set of halfspaces `A·x + b ≤ 0` (SciPy's convention — see below) and * a strictly **interior** point `x₀`, `halfspaceIntersection` returns the * **vertices** of the bounded polytope `{x : A·x + b ≤ 0}`. * * ## Convention (matches `scipy.spatial.HalfspaceIntersection`) * * Each halfspace is a row `[a_1, …, a_d, b]` of length `d + 1` denoting the * inequality * * ```text * a·x + b ≤ 0 (i.e. a·x ≤ −b) * ``` * * This is exactly SciPy's stacked `[A | b]` form (`Ax + b ≤ 0`). To feed a * constraint written `a·x ≤ c`, pass the row `[a_1, …, a_d, −c]`. * * ## Method — the dual-hull route (SciPy's approach) * * With a strictly interior point `x₀` (every `aᵢ·x₀ + bᵢ < 0`), map each * halfspace to a **dual point** * * ```text * yᵢ = aᵢ / dᵢ , dᵢ = −(aᵢ·x₀ + bᵢ) > 0. * ``` * * The convex hull of `{yᵢ}` is the polar dual of the (recentred) polytope: * **each facet of the dual hull corresponds to a vertex of the primal * polytope**, and the primal vertex is the point where the `d` halfspaces * spanning that facet meet — the solution of the `d × d` linear system * `aᵢ·x = −bᵢ` over those `d` halfspaces. Redundant (non-hull) halfspaces map to * interior dual points and contribute no vertex, exactly as SciPy discards them. * * **Boundedness.** The primal polytope is bounded iff the dual-space **origin** * lies strictly inside `conv{yᵢ}` (equivalently, the halfspace normals `aᵢ` * positively span `ℝᵈ`). This is checked against the oriented dual-hull facets; * an unbounded polytope throws — mirroring SciPy's `QhullError`. * * ## Dimensions * * Implemented for **2-D and 3-D** by reusing the package's `convexHull` * (monotone-chain / QuickHull). For `d > 3` a clear error is thrown: the * general n-D case needs an n-D convex hull (QuickHull-n) or the * **double-description method** (Motzkin — incrementally intersect halfspaces, * maintaining the V-representation with an LP/adjacency feasibility step), which * MathTS's hull does not yet provide. Not half-shipped. * * Pinned against `scipy.spatial.HalfspaceIntersection(halfspaces, * interior_point).intersections` (the vertex set, order-independent to ~1e-9) in * `functions/tests/geometry-halfspace-oracle.test.ts`. * * @packageDocumentation */ /** Structured halfspace-intersection result (mirrors SciPy's vertex output). */ export interface HalfspaceIntersectionResult { /** * Vertices of the bounded polytope `{x : A·x + b ≤ 0}` as coordinate arrays. * In 2-D they are ordered counter-clockwise (a polygon traversal); in 3-D the * order is unspecified (deduplicated). */ vertices: number[][]; /** * Vertex–facet incidence: `incidences[k]` lists the indices (into the input * `halfspaces`) of every halfspace that is **tight** (`a·v + b = 0`) at * `vertices[k]`. A true polytope vertex is tight on at least `d` halfspaces. */ incidences: number[][]; } /** * Enumerate the vertices of the bounded polytope defined by a set of halfspaces. * * @param halfspaces - Rows `[a_1, …, a_d, b]` denoting `a·x + b ≤ 0` * (SciPy's `Ax + b ≤ 0` convention). All rows must have length `d + 1`. * @param interiorPoint - A point `x₀` of length `d` that is **strictly interior** * to the polytope (every `aᵢ·x₀ + bᵢ < 0`). * @returns A {@link HalfspaceIntersectionResult} (vertices + vertex-facet incidence). * @throws When `d ∉ {2, 3}`; when a halfspace row is malformed; when * `interiorPoint` is not strictly interior; or when the polytope is unbounded. * * @example * // Unit square [0,1]² from its four edge halfspaces. * halfspaceIntersection( * [[-1, 0, 0], [1, 0, -1], [0, -1, 0], [0, 1, -1]], * [0.5, 0.5] * ).vertices; // the four corners (CCW) */ export declare function halfspaceIntersection(halfspaces: number[][], interiorPoint: number[]): HalfspaceIntersectionResult; //# sourceMappingURL=halfspace-intersection.d.ts.map