Source code for gunz_cm.structs.lazy_matrix

"""
Lazy-matrix view: a pure-data NamedTuple holding the recipe for
materializing a contact matrix without actually loading it.

``LazyMatrixView`` is the value type that replaces the implicit "lazy
load" behavior currently embedded in ``ContactMatrix.data`` (the
property at ``src/gunz_cm/matrix.py:152-164`` that triggers disk I/O on
first access). The lazy-load is **explicit** here: the view holds a
zero-arg callable and a kwargs dict, and the caller decides when to
materialize by calling ``.materialize()``.

DOP alignment: Principle 1 (separate code from data) + Principle 2
(immutable data). The view is a NamedTuple — pure data, no methods
beyond the auto-generated tuple protocol. The materialize operation is
a free function, not a method, so callers can substitute their own
materialization strategy (mock for tests, distributed load for large
matrices, etc.).

Examples
--------
>>> def loader(**kwargs):
...     import numpy as np
...     return np.zeros((2, 2))
>>> view = LazyMatrixView(loader=loader, kwargs={"path": "x.hic"})
>>> type(view).__name__
'LazyMatrixView'
>>> # .materialize() returns whatever the loader returns; not exercised
>>> # in this example because loader is a stub.

Notes
-----
Phase 1 introduces ``LazyMatrixView`` as a value type only. ``ContactMatrix``
is NOT modified to consume it. That swap happens in v2.19.0 (Phase 2).
This phase establishes the type; downstream phases consume it.

The ``loader`` field is typed as ``Callable[..., t.Any]`` rather than a
more specific protocol because the loader's signature depends on the
file format (Hi-C vs cooler vs GZCM). Tightening the type would force
every loader to share a signature, which they do not.
"""

from __future__ import annotations

import typing as t
from typing import NamedTuple


[docs]class LazyMatrixView(NamedTuple): """Immutable recipe for materializing a contact matrix on demand. Parameters ---------- loader : Callable[..., t.Any] Zero-argument-callable that, when invoked, returns the materialized contact matrix (typically a ``scipy.sparse.csr_matrix`` or ``numpy.ndarray``). The loader is invoked by :func:`materialize`, passing ``self.kwargs``. kwargs : dict[str, t.Any] Keyword arguments to pass to ``loader`` at materialize time. Stored as a plain ``dict`` (not a ``MappingProxyType``) for ergonomic ``view.kwargs["path"] = "x.hic"`` updates prior to materialization, since NamedTuples are immutable and we do not want to break the ergonomic "configure then load" pattern. Examples -------- """ loader: t.Callable[..., t.Any] kwargs: dict[str, t.Any]
[docs]def materialize(view: LazyMatrixView) -> t.Any: """Materialize a :class:`LazyMatrixView` by invoking its loader. This is the canonical way to convert a lazy view into concrete data. Free function (not a method on ``LazyMatrixView``) so the caller can substitute their own materialization strategy. Parameters ---------- view : LazyMatrixView The lazy view to materialize. Returns ------- t.Any Whatever ``view.loader(**view.kwargs)`` returns. Examples -------- >>> def fake(**kw): return kw >>> v = LazyMatrixView(loader=fake, kwargs={"x": 1}) >>> materialize(v) == {"x": 1} True """ return view.loader(**view.kwargs)
__all__ = ["LazyMatrixView", "materialize"]