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"]