Skip to content

Idea: support virtual table of LAPACK functions #413

Open

Description

@mdekstrand

This might more properly belong in lapack-sys, but it would be very useful to be able to reuse BLAS and LAPACK from SciPy when using lax and ndarray-linalg to build Python extension modules with PyO3.

SciPy exposes routines from the BLAS and LAPACK it was linked against in a manner that can be imported with Cython's cimport, in the modules scipy.linalg.cython_blas and scipy.linalg.cython_lapack, to allow other Python extension modules implemented using Cython to reuse BLAS and LAPACK instead of needing to supply their own copy. I am not sure the best way to identify and properly link against these functions; I have one working method at lenskit/lkpy#960, fishing a pointer to sposv out of Python at runtime (the Cython modules expose them in a Python dictionary).

I imagine an interface where a PyO3 extension module can do something like use lax with a python feature, then call a method like lax::init_from_python(py) in a module initializer to grab the proper function pointers and set them up for lax to use, after which the lax methods (and therefore ndarray-linalg) will work without needing to compile or link against a separate BLAS and LAPACK.

In shared-library settings, like Pixi/Conda or system packages, all of the different modules can directly link against the same "system" BLAS. However, Python binary wheels do not make that easy, and the general solution is for each package to statically link against BLAS, or to use SciPy's export if it depends on SciPy.

Activity

  1. shinaoka commented on Sep 10, 2026

    @shinaoka

    I maintain two crates that implement the runtime function-pointer injection layer discussed here:

    • cblas-inject accepts Fortran BLAS function pointers at runtime and exposes a CBLAS-compatible interface, including row-major handling.
    • lapack-inject accepts Fortran LAPACK function pointers and exports Fortran-style symbols such as dgesv_ and dgetrf_, intended to satisfy consumers using lapack-sys/lapack without linking a separate native LAPACK implementation.

    For example, the LAPACK registration API includes register_dgesv_lp64(ptr) and register_dgesv_ilp64(ptr). The default consumer-facing ABI remains LP64 even when an ILP64 host provider is registered.

    These could provide the dispatch layer for the proposed SciPy/PyO3 integration: obtain the pointers from SciPy's Cython exports during initialization, check their signatures/integer ABI, and register them before numerical calls. The BLAS crate takes Fortran BLAS pointers, so it does not require SciPy to expose CBLAS entry points.

    There is still integration work to verify for lax/ndarray-linalg: extracting the SciPy capsules, ensuring the providers remain alive, arranging linkage to the injection symbols without another BLAS/LAPACK provider, and covering the routines used by the caller. In particular, the currently documented lapack-inject subset does not include sposv, the example mentioned above. I have not validated this exact SciPy → injection → ndarray-linalg stack end to end.

    Sharing these as existing building blocks for this proposal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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