-
Notifications
You must be signed in to change notification settings - Fork 9
feat(math): add finite topological spaces domain with interior, closure, boundary, Kolmogorov quotient, and continuity check (#1920) #2037
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| """Supported native finite topological space API.""" | ||
|
|
||
| from jacobian.math.finite_topology_spaces.operations import ( | ||
| boundary, | ||
| closure, | ||
| continuous_check, | ||
| from_preorder, | ||
| interior, | ||
| kolmogorov_quotient, | ||
| minimal_neighbourhoods, | ||
| specialization_preorder, | ||
| ) | ||
| from jacobian.math.finite_topology_spaces.values import ( | ||
| FiniteTopologicalMap, | ||
| FiniteTopologicalSpace, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "FiniteTopologicalMap", | ||
| "FiniteTopologicalSpace", | ||
| "boundary", | ||
| "closure", | ||
| "continuous_check", | ||
| "from_preorder", | ||
| "interior", | ||
| "kolmogorov_quotient", | ||
| "minimal_neighbourhoods", | ||
| "specialization_preorder", | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| """Owner-local admission decisions for built-in math operations.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from jacobian.catalog.admission import AdmissionDecision, OperationAdmission | ||
|
|
||
| ADMISSIONS: tuple[OperationAdmission, ...] = ( | ||
| OperationAdmission( | ||
| "topology.finite.interior.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact interior via minimal open neighbourhood containment in an Alexandrov space", | ||
| ), | ||
| OperationAdmission( | ||
| "topology.finite.closure.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact closure via specialization preorder up-set", | ||
| ), | ||
| OperationAdmission( | ||
| "topology.finite.boundary.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact boundary as closure minus interior", | ||
| ), | ||
| OperationAdmission( | ||
| "topology.finite.kolmogorov_quotient.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact T0 quotient identifying points with the same minimal open neighbourhood", | ||
| ), | ||
| OperationAdmission( | ||
| "topology.finite.continuity_check.compute", | ||
| AdmissionDecision.KEEP, | ||
| "exact continuity check via specialization preorder monotonicity", | ||
| ), | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| """Typed wire contracts for finite topological space operations.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from pydantic import Field | ||
|
|
||
| from jacobian._models import StrictModel | ||
| from jacobian.math.finite_topology_spaces.values import ( | ||
| FiniteTopologicalMap, | ||
| FiniteTopologicalSpace, | ||
| ) | ||
|
|
||
|
|
||
| class SubsetRequest(StrictModel): | ||
| """Operate on a subset of points.""" | ||
|
|
||
| space: FiniteTopologicalSpace | ||
| subset: tuple[int, ...] = Field(default=()) | ||
|
Comment on lines
+14
to
+18
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Asking for the closure or boundary of a point number that does not exist crashes the request A request naming a point outside the space is accepted by the input model and then rejected deep inside the computation ( Unvalidated subset indices in SubsetRequest
The same unvalidated input behaves inconsistently for Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||
|
|
||
|
|
||
| class InteriorResult(StrictModel): | ||
| interior: tuple[int, ...] | ||
|
|
||
|
|
||
| class ClosureResult(StrictModel): | ||
| closure: tuple[int, ...] | ||
|
|
||
|
|
||
| class BoundaryResult(StrictModel): | ||
| boundary: tuple[int, ...] | ||
|
|
||
|
|
||
| class ContinuousCheckRequest(StrictModel): | ||
| """Check continuity of a point map.""" | ||
|
|
||
| point_map: FiniteTopologicalMap | ||
|
|
||
|
|
||
| class ContinuousCheckResult(StrictModel): | ||
| is_continuous: bool | ||
|
|
||
|
|
||
| class KolmogorovQuotientRequest(StrictModel): | ||
| space: FiniteTopologicalSpace | ||
|
|
||
|
|
||
| class KolmogorovQuotientResult(StrictModel): | ||
| quotient_points: tuple[str, ...] | ||
| quotient_preorder: tuple[tuple[int, ...], ...] | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "BoundaryResult", | ||
| "ClosureResult", | ||
| "ContinuousCheckRequest", | ||
| "ContinuousCheckResult", | ||
| "InteriorResult", | ||
| "KolmogorovQuotientRequest", | ||
| "KolmogorovQuotientResult", | ||
| "SubsetRequest", | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| """Domain adapter for finite topological space operations.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from jacobian.math.finite_topology_spaces._models import ( | ||
| BoundaryResult, | ||
| ClosureResult, | ||
| ContinuousCheckRequest, | ||
| ContinuousCheckResult, | ||
| InteriorResult, | ||
| KolmogorovQuotientRequest, | ||
| KolmogorovQuotientResult, | ||
| SubsetRequest, | ||
| ) | ||
| from jacobian.math.finite_topology_spaces.operations import ( | ||
| boundary, | ||
| closure, | ||
| continuous_check, | ||
| interior, | ||
| kolmogorov_quotient, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "compute_boundary", | ||
| "compute_closure", | ||
| "compute_continuous_check", | ||
| "compute_interior", | ||
| "compute_kolmogorov_quotient", | ||
| ] | ||
|
|
||
|
|
||
| def compute_interior(request: SubsetRequest) -> InteriorResult: | ||
| result = interior(request.space, frozenset(request.subset)) | ||
| return InteriorResult(interior=tuple(sorted(result))) | ||
|
|
||
|
|
||
| def compute_closure(request: SubsetRequest) -> ClosureResult: | ||
| result = closure(request.space, frozenset(request.subset)) | ||
| return ClosureResult(closure=tuple(sorted(result))) | ||
|
|
||
|
|
||
| def compute_boundary(request: SubsetRequest) -> BoundaryResult: | ||
| result = boundary(request.space, frozenset(request.subset)) | ||
| return BoundaryResult(boundary=tuple(sorted(result))) | ||
|
|
||
|
|
||
| def compute_continuous_check( | ||
| request: ContinuousCheckRequest, | ||
| ) -> ContinuousCheckResult: | ||
| result = continuous_check(request.point_map) | ||
| return ContinuousCheckResult(is_continuous=result) | ||
|
|
||
|
|
||
| def compute_kolmogorov_quotient( | ||
| request: KolmogorovQuotientRequest, | ||
| ) -> KolmogorovQuotientResult: | ||
| result = kolmogorov_quotient(request.space) | ||
| return KolmogorovQuotientResult( | ||
| quotient_points=result["quotient_points"], # type: ignore[arg-type] | ||
| quotient_preorder=result["quotient_preorder"], # type: ignore[arg-type] | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| """Finite topological space operation declarations.""" | ||
|
|
||
| from collections.abc import Callable | ||
| from typing import Any | ||
|
|
||
| from jacobian._models import StrictModel | ||
| from jacobian.catalog._examples import example | ||
| from jacobian.catalog.models import MathTool, OperationExample | ||
| from jacobian.math.finite_topology_spaces._models import ( | ||
| BoundaryResult, | ||
| ClosureResult, | ||
| ContinuousCheckRequest, | ||
| ContinuousCheckResult, | ||
| InteriorResult, | ||
| KolmogorovQuotientRequest, | ||
| KolmogorovQuotientResult, | ||
| SubsetRequest, | ||
| ) | ||
| from jacobian.math.finite_topology_spaces._operations import ( | ||
| compute_boundary, | ||
| compute_closure, | ||
| compute_continuous_check, | ||
| compute_interior, | ||
| compute_kolmogorov_quotient, | ||
| ) | ||
|
|
||
|
|
||
| def _op[ | ||
| RequestT: StrictModel, | ||
| ResultT: StrictModel, | ||
| ]( | ||
| operation_id: str, | ||
| title: str, | ||
| description: str, | ||
| request_model: type[RequestT], | ||
| result_model: type[ResultT], | ||
| operation: Callable[[RequestT], ResultT], | ||
| *tags: str, | ||
| examples: tuple[OperationExample, ...] = (), | ||
| version: str = "1", | ||
| ) -> MathTool[RequestT, ResultT]: | ||
| return MathTool( | ||
| operation_id=operation_id, | ||
| version=version, | ||
| title=title, | ||
| description=description, | ||
| request_type=request_model, | ||
| result_type=result_model, | ||
| run=operation, | ||
| tags=tags, | ||
| examples=examples, | ||
| ) | ||
|
|
||
|
|
||
| # A Sierpinski space: points {a, b}, preorder rows: a -> {a}, b -> {a, b} | ||
| # (a <= b in specialization order, so open sets are {}, {a}, {a,b}). | ||
| _SPACE = { | ||
| "points": ["a", "b"], | ||
| "preorder": [[0], [0, 1]], | ||
| } | ||
|
|
||
|
|
||
| TOPOLOGY_SPACE_OPERATIONS: tuple[MathTool[Any, Any], ...] = ( | ||
| _op( | ||
| "topology.finite.interior.compute", | ||
| "Compute the interior of a subset", | ||
| "Return the largest open set contained in the subset. In an " | ||
| "Alexandrov space, the interior consists of all points whose minimal " | ||
| "open neighbourhood is contained in the subset.", | ||
| SubsetRequest, | ||
| InteriorResult, | ||
| compute_interior, | ||
| "finite-topology", | ||
| "interior", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "sierpinski_interior", | ||
| "Interior of {b} in the Sierpinski space.", | ||
| {"space": _SPACE, "subset": [1]}, | ||
| ), | ||
| ), | ||
| ), | ||
| _op( | ||
| "topology.finite.closure.compute", | ||
| "Compute the closure of a subset", | ||
| "Return the smallest closed set containing the subset. The closure " | ||
| "of x is the up-set of x in the specialization preorder.", | ||
| SubsetRequest, | ||
| ClosureResult, | ||
| compute_closure, | ||
| "finite-topology", | ||
| "closure", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "sierpinski_closure", | ||
| "Closure of {a} in the Sierpinski space.", | ||
| {"space": _SPACE, "subset": [0]}, | ||
| ), | ||
| ), | ||
| ), | ||
| _op( | ||
| "topology.finite.boundary.compute", | ||
| "Compute the boundary of a subset", | ||
| "Return the boundary of a subset: closure minus interior.", | ||
| SubsetRequest, | ||
| BoundaryResult, | ||
| compute_boundary, | ||
| "finite-topology", | ||
| "boundary", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "sierpinski_boundary", | ||
| "Boundary of {a} in the Sierpinski space.", | ||
| {"space": _SPACE, "subset": [0]}, | ||
| ), | ||
| ), | ||
| ), | ||
| _op( | ||
| "topology.finite.kolmogorov_quotient.compute", | ||
| "Compute the T0 (Kolmogorov) quotient", | ||
| "Return the T0 quotient that identifies points with the same minimal " | ||
| "open neighbourhood, plus the class map.", | ||
| KolmogorovQuotientRequest, | ||
| KolmogorovQuotientResult, | ||
| compute_kolmogorov_quotient, | ||
| "finite-topology", | ||
| "kolmogorov-quotient", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "sierpinski_kolmogorov", | ||
| "T0 quotient of the Sierpinski space.", | ||
| {"space": _SPACE}, | ||
| ), | ||
| ), | ||
| ), | ||
| _op( | ||
| "topology.finite.continuity_check.compute", | ||
| "Check whether a point map is continuous", | ||
| "Return whether a point map between finite topological spaces is " | ||
| "continuous. A map f: X -> Y is continuous iff x' <= x implies " | ||
| "f(x') <= f(x) in the specialization preorders.", | ||
| ContinuousCheckRequest, | ||
| ContinuousCheckResult, | ||
| compute_continuous_check, | ||
| "finite-topology", | ||
| "continuity", | ||
| "exact", | ||
| examples=( | ||
| example( | ||
| "identity_continuous", | ||
| "The identity map is continuous.", | ||
| { | ||
| "point_map": { | ||
| "source": _SPACE, | ||
| "target": _SPACE, | ||
| "point_map": [0, 1], | ||
| }, | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
|
Comment on lines
+140
to
+165
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔍 New domain overlaps heavily with the existing finite_topology domain This domain duplicates concepts already owned by Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| ) | ||
|
|
||
| TOOLS = TOPOLOGY_SPACE_OPERATIONS | ||
|
|
||
| __all__ = ["TOOLS"] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔍 New domain is not registered in the root jacobian.math namespace
The package exposes a public
__all__and has an owner-localtest_public_api.py, butfinite_topology_spaceswas not added tosrc/jacobian/math/__init__.pyor toROOT_MATH_DOMAINSintests/math/public_api/test_namespace.py:18-43.from jacobian.math import finite_topology_spacesstill works as a submodule import so the new test passes, but the cross-owner invariants (no private names, one canonical owner per public callable) never run against this domain. Confirm whether omission from the root namespace is deliberate.Was this helpful? React with 👍 or 👎 to provide feedback.