Skip to content

refactor: simplify decorator type-dispatch system #276

@Jammy2211

Description

@Jammy2211

Overview

The decorator system at autoarray/structures/decorators/ handles input→output type mapping for all profile methods (e.g. Grid2D in → Array2D out, Grid2DIrregular → ArrayIrregular). It works correctly but is verbose (~648 lines), contains dead code (Grid1D path), duplicates logic across three Maker classes, and has near-zero dedicated test coverage. This task cleans it up in phases, starting with tests and targeted cleanup, with an optional follow-up to consolidate to a registry-based architecture.

Plan

  • Write comprehensive decorator unit tests covering all grid types × all decorators × edge cases (ndarray passthrough, JAX passthrough, list returns) — safety net before any refactoring
  • Remove the dead Grid1D code path from all makers — Grid1D is never passed to decorated profile methods
  • Extract shared list-return handling into a single helper used by all makers
  • Move over-sampling metadata extraction into Grid2D's construction rather than try/except in GridMaker
  • Rename grid_decdecorators in the public API (aa.grid_decaa.decorators) with grep-and-replace across PyAutoGalaxy/PyAutoLens
  • Phase 3 (follow-up): If tests are solid and cleanup goes well, consolidate the three Maker classes into one generic wrapper + flat lookup table (~530 lines → ~150 lines)
Detailed implementation plan

Affected Repositories

  • PyAutoArray (primary)
  • PyAutoGalaxy (consumer — decorator usage, rename)
  • PyAutoLens (consumer — decorator usage, rename)

Work Classification

Library

Branch Survey

Repository Current Branch Dirty?
PyAutoArray main clean
PyAutoGalaxy main clean
PyAutoLens main clean

Suggested branch: feature/data-typing-simplify
Worktree root: ~/Code/PyAutoLabs-wt/data-typing-simplify/

Implementation Steps

Phase 1 — Tests (zero-risk)

  1. Expand test_autoarray/test_decorators.py with tests for:
    • @to_array with Grid2D input → asserts Array2D output with correct mask
    • @to_array with Grid2DIrregular input → asserts ArrayIrregular output
    • @to_array with raw np.ndarray → asserts np.ndarray passthrough
    • @to_vector_yx with Grid2D → asserts VectorYX2D
    • @to_vector_yx with Grid2DIrregular → asserts VectorYX2DIrregular
    • @to_grid with Grid2D → asserts Grid2D with over-sampling metadata preserved
    • @to_grid with Grid2DIrregular → asserts Grid2DIrregular
    • @transform — coordinate frame transformation applied and reversed
    • List return handling for all decorators
    • JAX array passthrough (if jax available)

Phase 2 — Targeted cleanup (low risk)

  1. Remove Grid1D isinstance branch and via_grid_1d() from all three makers (to_array.py, to_grid.py, to_vector_yx.py) and the 1D projection logic from abstract.py
  2. Extract list-return handling from each maker into a shared helper in abstract.py
  3. Move over-sampling metadata try/except from GridMaker.via_grid_2d() into cleaner getattr calls or into Grid2D's own construction
  4. Rename grid_decdecorators in autoarray/__init__.py and update all aa.grid_dec. references in PyAutoGalaxy and PyAutoLens

Phase 3 — Registry consolidation (follow-up, moderate risk)

  1. Replace the three Maker classes with a single generic wrapper + lookup table:
    {(Grid2D, "array"): Array2D, (Grid2DIrregular, "array"): ArrayIrregular, ...}
    
  2. Keep external API (to_array, to_vector_yx, to_grid) as thin wrappers so downstream code doesn't change
  3. Run full test suites across PyAutoArray, PyAutoGalaxy, PyAutoLens

Key Files

  • autoarray/structures/decorators/abstract.py — base maker class, isinstance routing
  • autoarray/structures/decorators/to_array.py — ArrayMaker
  • autoarray/structures/decorators/to_grid.py — GridMaker (over-sampling complexity)
  • autoarray/structures/decorators/to_vector_yx.py — VectorYXMaker
  • autoarray/structures/decorators/transform.py — coordinate frame decorator
  • test_autoarray/test_decorators.py — currently near-empty (11 lines)
  • autoarray/__init__.py — exports grid_dec

Original Prompt

Click to expand starting prompt

The different data structures in PyAutoArray are quite confusing, in some ways:

  • Array2D
  • ArrayIrregular
  • Grid2D
  • GridIrregular

And so on.

They serve an important purpose, unifying the API and abstractions in a way which ensures a user can understand
that data and grids can be paired to something uniform or not. Furthermore, the slam / native API is important
in making both accessible, and streamlining how masked data vectors are stored.

First, we should assess if this code can be simplified at all or if its acceptable. I dont have a better idea.

You would probably benefit from reading @autolens_workspace/scripts/guides/data_structures.py to see how a user
interfaces with these objects.

However, things get more complex, as these objects are used to define mappings at the profile level of
@PyAutoGalaxy/autogalaxy/profiles. For example for this function:

class Isothermal(PowerLaw):
def init(self, centre, ell_comps, einstein_radius):
super().init(centre=centre, ell_comps=ell_comps, einstein_radius=einstein_radius, slope=2.0)

@aa.grid_dec.to_vector_yx
@aa.grid_dec.transform
def deflections_yx_2d_from(self, grid, xp=np, **kwargs):
    ...

The decorator @aa.grid_dec.to_vector_yx is used to understand that for this function, the result
that comes out must be a VectorYX object. It handles more typing, for example if a Grid2DIrregular comes in
a VectorYXIrregular comes out, but a Grid2D produces a VectorYX object.

There is also behaviour where if a numpy ndarray comes in, a numpy ndarray comes out without type casting,
with the same behaviour for a JAX array.

The problem is really just how complex things got in this decorator, which is all handled at
@PyAutoArray/autoarray/structures/decorators. Its complicated, messy and hard to trace.

So, can you give me your assessment of whether there's a quite large, sweeping restructure that can simplify this
code but retain the desired functionality and behaviour? Think hard, this could require a good chunk of planning
and no doubt extensive testing after!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions