@@ -16,9 +16,10 @@ This is a UV workspace repository containing multiple packages:
1616
1717- ** Language** : Python 3.11+
1818- ** Main API** : Vector types, coordinate transformations, and reference frames
19- - Vector types: ` CartesianPos3D ` , ` SphericalPos ` , ` CylindricalPos ` , etc.
20- - Angle and Distance types with units via ` unxt `
21- - ` vconvert() ` : Transform between coordinate representations
19+ - ` coordinax.angle.Angle ` and ` coordinax.distance.Distance ` types with units
20+ via ` unxt `
21+ - Vector types ` coordinax.Vector ` with representations in ` coordinax.r ` .
22+ - ` vconvert() ` : Transform between vector representations
2223 - Operators on vectors: ` GalileanRotateOp ` , ` GalileanBoostOp ` , etc.
2324 - Frame and their transformations: ` frames.frame_transform_op() `
2425 - Coordinates with frames: ` Coordinate ` .
@@ -30,9 +31,7 @@ This is a UV workspace repository containing multiple packages:
3031## Architecture & Core Components
3132
3233- ** Vector types** (hierarchical):
33- - ` AbstractPos ` : Base class for position vectors
34- - ` AbstractVel ` : Base class for velocity vectors
35- - ` AbstractAcc ` : Base class for acceleration vectors
34+ - ` AbstractRep ` : Base class for coordinate vectors
3635 - Concrete implementations: Cartesian, Spherical, Cylindrical, etc.
3736 - All vectors are ` ArrayValue ` subclasses (Quax protocol) for JAX integration
3837- ** Angle and Distance types** : Specialized scalar types with units
@@ -68,9 +67,9 @@ This is a UV workspace repository containing multiple packages:
6867### Main Package Structure (` /src/coordinax/ ` )
6968
7069- ` _src/ ` : Private implementation code
71- - ` vectors/ ` : Vector classes (position, velocity, acceleration)
7270 - ` angles.py ` : Angle type implementation
7371 - ` distances/ ` : Distance type implementations
72+ - ` vectors/ ` : Vector classes (position, velocity, acceleration)
7473 - ` frames/ ` : Reference frame definitions and transformations
7574 - ` operators/ ` : Frame-aware operators
7675- ` _coordinax_space_frames/ ` : Frame-specific coordinate spaces
@@ -81,6 +80,8 @@ This is a UV workspace repository containing multiple packages:
8180
8281- Always use type hints (standard typing, ` jaxtyping.Array ` , ` ArrayLike ` , shape
8382 annotations)
83+ - ** NEVER use ` from __future__ import annotations ` ** - causes issues with plum
84+ dispatch and runtime type introspection
8485- Extensive use of Plum multiple dispatch - check ` .methods ` on any function to
8586 see all dispatches
8687- Runtime type checking via ` beartype ` for validation
@@ -93,6 +94,151 @@ This is a UV workspace repository containing multiple packages:
9394- Prefer ` u.Q ` over ` u.Quantity ` for creating quantities (shorter and more
9495 concise)
9596
97+ ### Multiple Dispatch with Plum
98+
99+ This project heavily relies on ` plum-dispatch ` for multiple dispatch, which
100+ allows different implementations of the same function based on argument types.
101+ Understanding how plum works is critical for working with this codebase.
102+
103+ #### Multiple Dispatch Mechanism
104+
105+ - ** Single-dispatch vs Multiple-dispatch** : Unlike single dispatch (e.g.,
106+ ` functools.singledispatch ` ), plum selects implementations based on ALL
107+ argument types, not just the first one
108+ - ** Type-based routing** : Plum examines the runtime types of all arguments and
109+ selects the most specific matching implementation
110+ - ** Dispatch decorator** : Use ` @dispatch ` to register multiple implementations
111+ of the same function name
112+
113+ Example:
114+
115+ ``` python
116+ from plum import dispatch
117+
118+
119+ @dispatch
120+ def process (x : int ) -> str :
121+ return f " integer: { x} "
122+
123+
124+ @dispatch
125+ def process (x : float ) -> str :
126+ return f " float: { x} "
127+
128+
129+ @dispatch
130+ def process (x : int , y : int ) -> str :
131+ return f " two integers: { x} , { y} "
132+ ```
133+
134+ #### Finding All Dispatches
135+
136+ ** CRITICAL** : When working with dispatched functions, you MUST check all
137+ registered implementations. A function may have dozens of overloads.
138+
139+ ** Two methods to find all dispatches:**
140+
141+ 1 . ** Use ` .methods ` attribute** (preferred in Python REPL/notebooks):
142+
143+ ``` python
144+ from coordinax import vconvert
145+
146+ print (vconvert.methods) # Shows all registered dispatch signatures
147+ ```
148+
149+ 2 . ** Search the codebase** (preferred when coding):
150+ - Search for ` @dispatch ` followed by the function name
151+ - Look for all ` def function_name(...) ` definitions with ` @dispatch `
152+ - Example: searching for ` @dispatch\ndef vconvert ` finds all vconvert
153+ overloads
154+
155+ ** Why this matters:**
156+
157+ - You might find a more specific dispatch that handles your exact case
158+ - Prevents accidentally adding duplicate dispatches
159+ - Reveals the complete API surface and supported type combinations
160+ - Essential for understanding how different vector types interact
161+
162+ #### Parametric Classes
163+
164+ Plum's ` @parametric ` decorator enables type parametrization, creating distinct
165+ types for different parameters:
166+
167+ ``` python
168+ from plum import parametric
169+
170+
171+ @parametric
172+ class Container (type_parameter ):
173+ def __init__ (self , value ):
174+ self .value = value
175+
176+
177+ # Creates distinct types:
178+ IntContainer = Container[int ]
179+ FloatContainer = Container[float ]
180+ ```
181+
182+ ** In this codebase:**
183+
184+ - Vector types can be parametric (though less common than in ` unxt ` )
185+ - Enables type-aware multiple dispatch for vector transformations
186+ - Example: Different dispatch paths based on vector representation type
187+
188+ ** Key properties:**
189+
190+ - Parametric types are cached (same parameters = same type object)
191+ - Type parameters can be strings, tuples, or other hashable objects
192+ - Use ` get_type_parameter(obj) ` to retrieve the parameter from an instance
193+ - Parametric classes enable representation checking at dispatch time
194+
195+ #### Type Promotion with ` plum.promote `
196+
197+ ` plum.promote ` implements automatic type promotion for mixed-type operations:
198+
199+ ``` python
200+ from plum import dispatch, promote
201+
202+
203+ @dispatch
204+ def add (x : int , y : int ) -> int :
205+ return x + y
206+
207+
208+ @dispatch
209+ def add (x : float , y : float ) -> float :
210+ return x + y
211+
212+
213+ # Without promotion:
214+ add(1 , 2.5 ) # Error: no dispatch for (int, float)
215+
216+
217+ # With promotion (defined separately):
218+ @dispatch
219+ def add (x : promote(int , float ), y : float ) -> float :
220+ return add(float (x), y)
221+ ```
222+
223+ ** In this codebase:**
224+
225+ - ` plum.promote ` is used to convert between vector types and representations
226+ - Common pattern: promote scalars to distance/angle types
227+ - Enables natural operations like ` vector + CartesianPos3D(...) `
228+
229+ ** Usage pattern:**
230+
231+ 1 . Define core implementations for specific types
232+ 2 . Add promotion dispatches to handle mixed types
233+ 3 . Promotion dispatches typically convert arguments and redispatch
234+
235+ ** Important notes:**
236+
237+ - Promotion order matters: ` promote(int, float) ` != ` promote(float, int) `
238+ - Keep promotion logic explicit and minimal
239+ - Prefer concrete dispatches over heavy promotion use
240+ - Document promotion behavior when it's non-obvious
241+
96242### JAX Integration via Quax
97243
98244- Vectors are ` ArrayValue ` subclasses (Quax protocol)
@@ -127,11 +273,18 @@ This is a UV workspace repository containing multiple packages:
127273 - ` nox -s docs ` : build documentation (add ` --serve ` to preview)
128274 - ` nox -s pytest_benchmark ` : run CodSpeed benchmarks
129275
276+ ** IMPORTANT** : Never write temporary files outside the repository (e.g., to
277+ ` /tmp/ ` or other system directories). Always use paths within the repository for
278+ any file operations, including temporary or scratch files.
279+
130280## Testing
131281
132282- Use ` pytest ` for all test suites with Sybil for doctests in code and markdown
133283- Add unit tests for every new function or class
134284- Test organization: ` unit/ ` , ` integration/ ` , ` benchmark/ `
285+ - ** All tests must actually test something** : Every test function must include
286+ ` assert ` statements or return values that pytest can validate. Empty test
287+ bodies or tests that only call functions without verification are not valid.
135288- Optional dependencies handled via
136289 ` optional_dependencies.OptionalDependencyEnum `
137290 - Tests requiring optional deps auto-skip if not installed
0 commit comments