Skip to content

Commit 0ba0fe7

Browse files
authored
♻️ refactor: chart(manifold) (#517)
♻️ refactor: consolidate charts, internal, manifolds ✨ feat(manifolds): introduce AbstractTopologicalManifold and NoManifold ✨ feat(charts): add manifold field to AbstractChart ♻️ refactor(manifolds): move eligible charts to module-level WeakSet 🐛 fix: resolve dataclass field ordering and chart strategy bugs from manifold field ♻️ refactor(manifolds): consolidate custom_types into _src/custom_types ♻️ refactor(manifolds): use internal imports instead of public coordinax.charts ♻️ refactor: promote exceptions.py from _src/charts/ to _src/ ♻️ refactor: consolidate product subpackage under _src/product/ ♻️ refactor: merge AbstractDiagonalMetric into base_metric and promote euclidean/ to _src/ ♻️ refactor: consolidate spherical charts and promote spherical/ to _src/ ♻️ refactor: promote embedded/ subpackage from manifolds/ to _src/ ♻️ refactor: promote minkowski/ subpackage from manifolds/ to _src/ ♻️ refactor: promote custom/ subpackage from manifolds/ to _src/ ♻️ refactor(internal): drop leading underscore from internal module filenames ✨ feat(euclidean): add Rn alias and __pdoc__ to EuclideanManifold ♻️ refactor(charts): rename AbstractChart.manifold field to M 🧱 infra(_src): add empty __init__.py ✨ feat(manifolds): add `Sn` alias and `__pdoc__` to `HyperSphericalManifold` ✨ feat(charts/manifolds): charts now carry sensible default manifolds ♻️ refactor: rename `manifold` attribute/param to `M` throughout ✨ feat(charts): register 1D chart with EuclideanAtlas ♻️ refactor(manifolds): simplify scale_factors to chart-only signature ♻️ refactor(manifolds): simplify angle_between to chart-only signature 🩹 fix-simple(charts): rename fixed_kwargs to fixed_kw and reformat long lines ♻️ refactor(vectors): derive M from chart instead of storing it as a field ♻️ refactor(manifolds): consolidate no_manifold into separate module ♻️ refactor(base): move chart imports to TYPE_CHECKING blocks 🏷️ types(ty): ignores ♻️ refactor(manifolds): consolidate AbstractTopologicalManifold into AbstractManifold ✨ feat(manifolds): consolidate null manifold objects into dedicated module ♻️ refactor: consolidate base classes into dedicated base/ module ✨ feat(embedded): add M property to EmbeddedChart 🐛 fix(hypothesis): exclude EmbeddedChart from vector strategy ♻️ refactor(charts): clean up decorators and type annotations ♻️ refactor(hypothesis): simplify vectors dispatch ## Summary of Changes ### **Architecture & Module Organization** - Consolidated charts, internal, and manifolds into cohesive structure - Promoted subpackages from `manifolds/` to top-level `_src/`: euclidean, spherical, embedded, minkowski, custom, product - Consolidated product files (charts, manifolds, spacetime) into unified `_src/product/` - Moved base classes (atlas, charts, manifold, metric) into dedicated `_src/base/` subdirectory - Elevated `exceptions.py` from `_src/charts/` to `_src/` for shared access - Eliminated `manifolds/custom_types.py` by redirecting imports to canonical `coordinax._src.custom_types` ### **Core API Changes** - **Manifold field on charts**: Added optional `manifold` field (later renamed to `M`) to `AbstractChart`, linking each chart to its topological manifold - **Manifold hierarchy simplification**: Merged separate `AbstractTopologicalManifold` into main `AbstractManifold` class - **Null objects consolidation**: Created dedicated `coordinax._src.null` module for `NoManifold`, `NoAtlas`, and new `NoMetric` sentinel - **Vector refactoring**: Removed redundant `M` field from `Point` and `AbstractVector`; now derived as computed property from chart ### **Defaults & Aliases** - Charts now carry sensible default manifolds (Cartesian charts → `Rn(n)`, spherical → `Sn(n)`) - Added `Rn` alias for `EuclideanManifold` with `__pdoc__` pretty-printing - Added `Sn` alias for `HyperSphericalManifold` with `__pdoc__` pretty-printing - Introduced `guess_manifold` dispatch system for automatic manifold inference ### **Signature Simplifications** - `scale_factors`: Removed manifold/metric positional argument; chart carries its manifold via `chart.M` - `angle_between`: Removed manifold/metric positional argument; mirrors `scale_factors` refactor - Renamed `manifold` attribute/parameter to `M` throughout (charts, vectors, point objects) ### **Import & Dependency Management** - Replaced public `coordinax.charts` imports with direct `coordinax._src` or `coordinax.api` imports in internal modules - Moved `coordinax.charts` imports to `TYPE_CHECKING` blocks in base modules to resolve circular dependencies - Updated all imports across hypothesis strategies, interop packages, and documentation ### **Internal Cleanup** - Dropped leading underscores from internal module filenames (`_dtype_utils.py` → `dtype_utils.py`, etc.) - Renamed `fixed_kwargs` → `fixed_kw` and reformatted long lines in register_ptmap - Added `@jax.tree_util.register_static` decorators and `@override` markers - Added empty `__init__.py` to `_src/` for package structure - Removed redundant `chart_dataclass_decorator` applications ### **Bug Fixes & Validation** - Fixed dataclass field ordering: `AbstractChart.manifold` now KW_ONLY to avoid interfering with positional fields - Fixed `NoManifold` dataclass implementation so `dataclassish.field_items` works - Fixed `CartesianProductChart.manifold` ClassVar override to remove spurious init parameter - Fixed hypothesis chart strategy `_param_filter` to skip KW_ONLY params with defaults - Excluded `EmbeddedChart` from vector strategy (not yet supported) - Added `M` property to `EmbeddedChart` returning combined intrinsic/ambient manifold ### **Documentation & Spec Updates** - Updated spec.md with topological-vs-smooth manifold distinction - Updated all docs, guides, tutorials, and hypothesis strategies to use new `M` naming - Propagated changes to `coordinax.api`, `coordinax.astro`, `coordinax.interop.astropy` - Added manifold `M` to chart `__pdoc__` (always shown, never hidden)
1 parent 104bfe0 commit 0ba0fe7

167 files changed

Lines changed: 2998 additions & 2613 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def _import_path_with_namespace(path: pathlib.Path) -> ModuleType:
165165
166166
Sybil receives filesystem paths. Without this mapping, those files may be
167167
imported as top-level modules (e.g. ``charts._src``), causing duplicate
168-
module identities versus ``coordinax.charts._src``.
168+
module identities versus ``coordinax._src.charts``.
169169
"""
170170
resolved_path = path.resolve()
171171
for root, namespace in RESOLVED_MODULE_ROOTS:

docs/api/charts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ cart_of_sph = cxc.cartesian_chart(sph)
4747

4848
### Chart Families
4949

50-
The module exports both concrete chart classes and predefined singleton-style instances.
50+
The module exports both concrete chart classes and predefined instances.
5151

5252
### 0D Charts
5353

docs/api/transforms.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ out = cxfm.act(frame_op, None, v)
4141
- `Scale`: Cartesian linear scaling
4242
- `Shear`: Cartesian linear shear
4343
- `Composed`: ordered transform composition
44-
- `identity`: convenience singleton instance of `Identity`
44+
- `identity`: convenience instance of `Identity`
4545

4646
## Transformation Group Classes (Markers)
4747

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
("py:class", "coordinax.representations._src.semantics.AbstractSemanticKind"),
116116
("py:class", "coordinax.representations._src.geom.PointGeometry"),
117117
("py:class", "coordinax.representations._src.basis.AbstractBasis"),
118-
("py:class", "coordinax.charts._src.d3.LonLatSpherical3D"),
118+
("py:class", "coordinax._src.charts.d3.LonLatSpherical3D"),
119119
]
120120

121121
# TypedNdArray is a JAX-private type (jax._src.basearray) with no public docs.

docs/conventions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ See [Glossary: Multiple Dispatch, Promotion](glossary.md); [plum documentation](
255255

256256
### Pre-Defined Chart Instances
257257

258-
For convenience, modules provide lowercase singleton instances:
258+
For convenience, modules provide lowercase instances:
259259

260260
- `cart3d`: Instance of `Cartesian3D`
261261
- `sph3d`: Instance of `Spherical3D`

docs/glossary.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ cconvert Function
144144
API for converting object representation. Usage: `cconvert(target_representation, current_object)`. Returns semantically equivalent object in new form. See [Conventions § Representation Conversion](conventions.md#representation-conversion-cconvert).
145145
146146
Chart Instance
147-
Lowercase singleton instance of a chart for convenience, e.g., `cart3d` (instance of `Cartesian3D`), `sph3d` (instance of `Spherical3D`). See [Conventions § Pre-Defined Chart Instances](conventions.md#pre-defined-chart-instances).
147+
Lowercase instance of a chart for convenience, e.g., `cart3d` (instance of `Cartesian3D`), `sph3d` (instance of `Spherical3D`). See [Conventions § Pre-Defined Chart Instances](conventions.md#pre-defined-chart-instances).
148148
149149
Chart Class
150150
Uppercase class defining a coordinate system template, e.g., `Cartesian3D`, `Spherical3D`. Instantiate to create specific charts.

docs/guides/charts.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Chart selection is independent of point data:
5050
>>> import coordinax.charts as cxc
5151
5252
>>> cxc.cartesian_chart(cxc.sph3d)
53-
Cart3D()
53+
Cart3D(M=Rn(3))
5454
```
5555

5656
## Inferring Charts And Normalizing Inputs
@@ -62,10 +62,10 @@ Cart3D()
6262
>>> import unxt as u
6363
6464
>>> cxc.guess_chart({"x": 1.0, "y": 2.0, "z": 3.0})
65-
Cart3D()
65+
Cart3D(M=Rn(3))
6666
6767
>>> cxc.guess_chart(frozenset(("x", "y", "z")))
68-
Cart3D()
68+
Cart3D(M=Rn(3))
6969
7070
>>> q = u.Q([1.0, 2.0, 3.0], "m")
7171
>>> cxc.cdict(q)

docs/guides/frames.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ import coordinax.frames as cxf
357357

358358
coord = cx.Point.from_([1, 2, 3], "kpc", cxf.alice)
359359
print(coord.frame) # Alice()
360-
print(coord.chart) # Cart3D()
360+
print(coord.chart) # Cart3D(M=Rn(3))
361361
```
362362

363363
### Frame Transformations On Coordinates
@@ -392,7 +392,7 @@ import coordinax.charts as cxc
392392
coord_cart = cx.Point.from_([1, 2, 3], "m", cxf.alice)
393393
coord_sph = coord_cart.cconvert(cxc.sph3d)
394394

395-
print(coord_cart.frame, coord_cart.chart) # Alice(), Cart3D()
395+
print(coord_cart.frame, coord_cart.chart) # Alice(), Cart3D(M=Rn(3))
396396
print(coord_sph.frame, coord_sph.chart) # Alice(), Spherical3D()
397397
```
398398

docs/guides/manifolds.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ If you only need raw chart transforms, use the charts guide. If you need compati
2626
>>> M = cxm.EuclideanManifold(3)
2727
>>> M.ndim
2828
3
29-
>>> M.default_chart
30-
Cart3D()
29+
>>> M.default_chart()
30+
Cart3D(M=Rn(3))
3131
3232
>>> M.has_chart(cxc.cart3d)
3333
True
@@ -48,8 +48,8 @@ False
4848
>>> import coordinax.manifolds as cxm
4949
5050
>>> E2 = cxm.EuclideanManifold(2)
51-
>>> E2.default_chart
52-
Cart2D()
51+
>>> E2.default_chart()
52+
Cart2D(M=Rn(2))
5353
>>> E2.has_chart(cxc.cart2d)
5454
True
5555
>>> E2.has_chart(cxc.polar2d)
@@ -65,8 +65,8 @@ True
6565
>>> import coordinax.manifolds as cxm
6666
6767
>>> S2 = cxm.HyperSphericalManifold()
68-
>>> S2.default_chart
69-
SphericalTwoSphere()
68+
>>> S2.default_chart()
69+
SphericalTwoSphere(M=Sn(2))
7070
>>> S2.has_chart(cxc.sph2)
7171
True
7272
>>> S2.has_chart(cxc.cart2d)
@@ -82,7 +82,7 @@ Use `guess_manifold` when you have data or a chart and need a manifold object.
8282
>>> import coordinax.manifolds as cxm
8383
8484
>>> cxm.guess_manifold({"x": 1, "y": 2, "z": 3})
85-
EuclideanManifold(ndim=3)
85+
Rn(3)
8686
8787
>>> cxm.guess_manifold(cxc.sph2)
8888
HyperSphericalManifold(ndim=2)
@@ -204,9 +204,9 @@ Use `EmbeddedChart` for compact chart-facing embed/project operations.
204204
205205
>>> embedded = cxm.EmbeddedChart(cxm.TwoSphereIn3D(radius=u.Q(1, "km")))
206206
>>> embedded.intrinsic
207-
SphericalTwoSphere()
207+
SphericalTwoSphere(M=Sn(2))
208208
>>> embedded.ambient
209-
Spherical3D()
209+
Spherical3D(M=Rn(3))
210210
211211
>>> p_intrinsic = {"theta": u.Q(1.0, "rad"), "phi": u.Q(0.5, "rad")}
212212
>>> p_ambient = cxm.pt_embed(p_intrinsic, embedded)

docs/guides/vectors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ import coordinax.charts as cxc
244244
coord_cart = cx.Point.from_([1, 2, 3], "m", cxf.alice)
245245
coord_sph = coord_cart.cconvert(cxc.sph3d)
246246

247-
print(coord_cart.chart) # Cart3D()
247+
print(coord_cart.chart) # Cart3D(M=Rn(3))
248248
print(coord_sph.chart) # Spherical3D()
249249

250250
print(coord_cart.frame) # Alice()

0 commit comments

Comments
 (0)