Springe zum Hauptinhalt
Ctrl+K

SciPy

  • Installation
  • Benutzerhandbuch
  • API-Referenz
  • Kompilieren aus dem Quellcode
  • Entwicklung
  • Release-Hinweise
  • GitHub
  • Scientific Python Forum
  • Installation
  • Benutzerhandbuch
  • API-Referenz
  • Kompilieren aus dem Quellcode
  • Entwicklung
  • Release-Hinweise
  • GitHub
  • Scientific Python Forum

Abschnittsnavigation

Informationen für Mitwirkende

  • Verhaltenskodex von SciPy
  • Möglichkeiten zur Mitwirkung
  • Schnellstartanleitung für Mitwirkende
  • Entwicklungsworkflow
  • Handbuch für SciPy-Mitwirkende

Roadmap

  • SciPy-Roadmap
  • Detaillierte SciPy-Roadmap
  • Toolchain-Roadmap

SciPy-Organisation

  • Handbuch für SciPy-Kernentwickler
  • Handbuch für die SciPy-API-Entwicklung
  • Projektverwaltung von SciPy
  • Entwicklerdokumentation
  • Handbuch für SciPy-Mitwirkende
  • Fehlerbehebung bei Problemen mit linearer Algebra

Fehlerbehebung bei Problemen mit linearer Algebra#

Fehlerberichte im Zusammenhang mit linearer Algebra gehören zu den anspruchsvollsten Problemen bei Diagnose und Behebung. Dies liegt nicht nur daran, dass lineare Algebra mathematisch/algorithmisch herausfordernd sein kann (was für viele Teile von SciPy gilt), sondern auch daran, dass BLAS/LAPACK-Bibliotheken eine komplexe Abhängigkeit zur Build-Zeit und zur Laufzeit darstellen – und wir unterstützen eine beträchtliche Anzahl von BLAS/LAPACK-Bibliotheken.

Dieses Dokument soll Anleitungen zur Fehlerbehebung bei Problemen mit linearer Algebra geben.

Wenn es einen echten Fehler gibt, kann dieser an drei Stellen liegen

  • In der verwendeten BLAS-Bibliothek,

  • In SciPy's Bindings für BLAS oder LAPACK (generiert durch numpy.f2py und/oder Cython),

  • Im algorithmischen Code von SciPy.

Ein wichtiger erster Schritt ist die Bestimmung, ob der Fehler in SciPy oder in der BLAS-Bibliothek liegt. Um die beiden am effizientesten zu unterscheiden, ist es am besten, Ihre Umgebung so einzurichten, dass Sie zur Laufzeit zwischen verschiedenen BLAS-Bibliotheken wechseln können (etwas, das wir nicht standardmäßig unterstützen und mit SciPy-Wheels von PyPI nicht möglich ist).

Autoren von Upstream-BLAS-Bibliotheken bevorzugen dringend saubere Reproduzierer (genau wie wir), was bedeutet: keine Python-Beteiligung. Daher wird dieser Leitfaden auch die Erstellung von Reproduzierern in C oder Fortran behandeln.

Finden der verwendeten BLAS-Bibliothek#

SciPy verfügt über eine Funktion, show_config, um die Build-Konfiguration eines installierten Pakets zu introspektieren. Dies ermöglicht die Abfrage von Details zu BLAS und LAPACK. Z.B.:

>>> blas_dep = scipy.show_config(mode='dicts')['Build Dependencies']['blas']
>>> for key in blas_dep:
...     print(f"{key}:  {blas_dep[key]}")
...
name:  openblas
found:  True
version:  0.3.23
detection method:  pkgconfig
include directory:  /home/user/miniforge/envs/scipy-dev/include
lib directory:  /home/user/miniforge/envs/scipy-dev/lib
openblas configuration:  USE_64BITINT=0 DYNAMIC_ARCH=1 DYNAMIC_OLDER= NO_CBLAS= NO_LAPACK=0 NO_LAPACKE= NO_AFFINITY=1 USE_OPENMP=0 PRESCOTT MAX_THREADS=128
pc file directory:  /home/user/miniforge/envs/scipy-dev/lib/pkgconfig

Diese Methode ist für SciPy-Wheels und lokale Entwicklungs-Builds korrekt. Sie *kann* für andere Installationen korrekt sein. Beachten Sie jedoch, dass Distributionen wie conda-forge und Debian möglicherweise gegen Stub-Bibliotheken bauen (typischerweise blas.so/lapack.so) und dann eine andere Bibliothek für den Benutzer installieren. In solchen Fällen werden selbst dann einfache blas und lapack berichtet, wenn beispielsweise OpenBLAS oder MKL in der Umgebung installiert sind. Für solche Installationen kann threadpoolctl normalerweise berichten, welche tatsächliche BLAS-Bibliothek in Gebrauch ist (es sei denn, es berichtet nicht über einfaches Netlib BLAS, siehe threadpoolctl#159).

$ python -m threadpoolctl -i scipy.linalg
[
  {
    "user_api": "blas",
    "internal_api": "openblas",
    "prefix": "libopenblas",
    "filepath": "/home/user/miniforge/envs/dev/lib/libopenblasp-r0.3.21.so",
    "version": "0.3.21",
    "threading_layer": "pthreads",
    "architecture": "SkylakeX",
    "num_threads": 24
  }
]

Weitere introspektive Methoden, die in lokalen Entwicklungsumgebungen hilfreich sein können, sind:

  1. Überprüfung von Abhängigkeiten von Shared Libraries

$ ldd build/scipy/linalg/_fblas.cpython-*.so
...
libopenblas.so.0 => /home/user/miniforge/envs/scipy-dev/lib/libopenblas.so.0 (0x0000780d6d000000)
% otool -L build/scipy/linalg/_fblas.cpython-310-darwin.so
build/scipy/linalg/_fblas.*.so:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.61.1)
    @rpath/libopenblas.0.dylib (compatibility version 0.0.0, current version 0.0.0)
  1. Prüfen, ob die verlinkte Bibliothek ein gegebenes Symbol enthält. Z.B. installiert conda-forge eine libblas.so, die jede unterstützte Bibliothek sein kann.

$ nm -gD ~/miniforge/envs/scipy-dev/lib/libblas.so | rg openblas_set_num_threads
0000000000362990 T openblas_set_num_threads
% nm ~/miniforge/envs/scipy-dev/lib/libblas.3.dylib | rg openblas_set_num_threads
000000000015b6b0 T _openblas_set_num_threads

Einrichtung Ihrer Umgebung zum Wechseln von BLAS-Bibliotheken#

Wir werden verschiedene Methoden zum Wechseln zwischen verschiedenen BLAS-Bibliotheken behandeln, da die einfachste Methode von Ihrem Betriebssystem/Ihrer Distribution und davon abhängen kann, ob Sie eine veröffentlichte Version von SciPy oder einen Entwicklungs-Build wünschen.

Conda-forge#

Die vielleicht einfachste Methode ist die Nutzung der von Distributionen bereitgestellten Laufzeit-Switching-Fähigkeiten. Um beispielsweise eine Conda-Umgebung mit der neuesten SciPy-Version zu erstellen und dann zwischen OpenBLAS, Netlib BLAS/LAPACK und MKL zu wechseln, ist dies so einfach wie:

$ mamba create -n blas-switch scipy threadpoolctl
$ mamba activate blas-switch
$ python -m threadpoolctl -i scipy.linalg
...
    "user_api": "blas",
    "internal_api": "openblas",

$ mamba install "libblas=*=*netlib"
...
  libblas                         3.9.0-21_linux64_openblas --> 3.9.0-5_h92ddd45_netlib
  libcblas                        3.9.0-21_linux64_openblas --> 3.9.0-5_h92ddd45_netlib
  liblapack                       3.9.0-21_linux64_openblas --> 3.9.0-5_h92ddd45_netlib

$ mamba install "libblas=*=*mkl"
...
  libblas                           3.9.0-5_h92ddd45_netlib --> 3.9.0-21_linux64_mkl
  libcblas                          3.9.0-5_h92ddd45_netlib --> 3.9.0-21_linux64_mkl
  liblapack                         3.9.0-5_h92ddd45_netlib --> 3.9.0-21_linux64_mkl

$ python -m threadpoolctl -i scipy.linalg
...
  "user_api": "blas",
  "internal_api": "mkl",

Dies kann auch für Entwicklungs-Builds geschehen, wenn über dev.py auf dieselbe Weise gebaut wird wie im Conda-Forge-Build-Rezept von SciPy (Ausgaben zur Kürze weggelassen, sie ähneln den obigen).

$ mamba env create -f environment.yml
$ mamba activate scipy-dev
$ mamba install "libblas=*=*netlib"  # necessary, we need to build against blas/lapack
$ python dev.py build -C-Dblas=blas -C-Dlapack=lapack -C-Duse-g77-abi=true
$ python dev.py test -s linalg  # run tests to verify
$ mamba install "libblas=*=*mkl"
$ python dev.py test -s linalg
$ mamba install "libblas=*=*openblas"

Linux-Distributionen Paketmanager#

Eine Reihe von Linux-Distributionen verwendet den update-alternatives Mechanismus, um über den Systempaketmanager zwischen verschiedenen BLAS-Bibliotheken wechseln zu können. Beachten Sie, dass dies ein generischer Mechanismus zur Verwaltung von "mehreren Implementierungen derselben Bibliothek oder Werkzeugs" ist, anstatt etwas Spezifisches für BLAS/LAPACK. Es ähnelt der obigen conda-forge-Methode, da es sowohl für von der Distribution bereitgestellte scipy-Pakete als auch für Entwicklungs-Builds gegen die Referenz libblas/liblapack-Schnittstellen funktioniert.

Die Schnittstelle sieht wie folgt aus

$ update-alternatives --config libblas.so.3
$ update-alternatives --config liblapack.so.3

was ein Menü im Terminal mit allen verfügbaren Bibliotheken zur Auswahl öffnet. Da die Benutzeroberfläche und die verfügbaren Optionen zwischen den Distributionen variieren dürften, verlinken wir hier auf die Debian-Dokumentation für BLAS/LAPACK-Switching und vermeiden eine detailliertere Dokumentation, wie dies auf anderen Distributionen funktioniert.

Beachten Sie, dass Fedora eine Ausnahme darstellt; es ist die einzige Distribution, die FlexiBLAS (siehe nächster Abschnitt für mehr Details) anbietet und die Installation mehrerer BLAS-Bibliotheken parallel ermöglicht, sodass ein echter Laufzeitwechsel ohne Aufruf des Systempaketmanagers möglich wird. Siehe die Fedora-Dokumentation zur Auswahl auf System- und Benutzerebene für weitere Details.

FlexiBLAS#

FlexiBLAS bietet Laufzeit-Switching-Unterstützung (unter anderem) für alle installierten BLAS-Bibliotheken, die es erkennen kann. Zum Zeitpunkt des Schreibens (März 2024) gibt es einige Einschränkungen, hauptsächlich: keine Unterstützung für Windows, keine Unterstützung für macOS Accelerate (die aktualisierte Version mit NEWLAPACK-Symbolen). Wenn diese Einschränkungen für Sie keine Rolle spielen, kann FlexiBLAS ein sehr nützliches Werkzeug für die effiziente Fehlerbehebung sein, einschließlich Versionen von OpenBLAS und anderen BLAS-Bibliotheken, die Sie aus dem Quellcode kompilieren müssen.

Sobald Sie alles eingerichtet haben, sieht die Entwicklungserfahrung so aus:

$ python dev.py build -C-Dblas=flexiblas -C-Dlapack=flexiblas
$ FLEXIBLAS=NETLIB python dev.py test -s linalg
$ FLEXIBLAS=OpenBLAS python dev.py test -s linalg
# Or export the environment variable to make the selection stick:
$ export FLEXIBLAS=OpenBLAS

Sie können auch einen Pfad zu einer kompilierten BLAS-Bibliothek angeben (z. B. FLEXIBLAS="libbhlas_atlas.so") – siehe die Nutzungsdokumentation in seiner README für weitere Details.

Sofern Sie nicht auf Fedora sind, müssen Sie FlexiBLAS wahrscheinlich aus dem Quellcode kompilieren, was etwas Aufwand bedeutet. Die gute Nachricht ist, dass dies funktionieren sollte, egal ob Sie unter Linux oder macOS sind und Python über virtuelle Umgebungen, Conda-Umgebungen oder auf andere Weise verwenden. Wir werden durchgehen, wie OpenBLAS und FlexiBLAS aus dem Quellcode kompiliert werden, um zu debuggen, ob etwas in der neuesten OpenBLAS-Version anders ist als bei Netlib BLAS/LAPACK (oder MKL) oder nicht.

Das Folgende sollte in jeder Umgebung funktionieren, in der Sie SciPy selbst kompilieren können. Das einzige zusätzliche Werkzeug, das wir benötigen, ist CMake (installieren Sie es z. B. mit pip install cmake).

Jedes Repository klonen

$ cd ..  # starting from the root of the local `scipy` repo
$ mkdir flexiblas-setup && cd flexiblas-setup
$ git clone https://github.com/OpenMathLib/OpenBLAS.git openblas
$ git clone https://github.com/mpimd-csc/flexiblas.git
$ mkdir built-libs  # our local prefix to install everything to

OpenBLAS kompilieren

$ cd openblas
$ mkdir build && cd build
$ cmake .. -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=$PWD/../../built-libs
$ cmake --build . -j
$ cmake --install . --prefix $PWD/../../built-libs
$ cd ../..

FlexiBLAS kompilieren

$ cd flexiblas
$ mkdir build && cd build
$ # Note: this will also pick up the libraries in your system/env libdir
$ cmake .. -DEXTRA="OpenBLAS" -DLAPACK_API_VERSION=3.9.0 \
    -DOpenBLAS_LIBRARY=$PWD/../../built-libs/lib/libopenblas.so \
    -DCMAKE_INSTALL_PREFIX=$PWD/../../built-libs
$ cmake --build . -j
$ cmake --install . --prefix $PWD/../../built-libs
$ cd ../..

Wir sind nun bereit, SciPy gegen FlexiBLAS zu kompilieren

$ export PKG_CONFIG_PATH=$PWD/flexiblas-setup/built-libs/lib/pkgconfig/
$ cd scipy
$ python dev.py build -C-Dblas=flexiblas -C-Dlapack=flexiblas
...
Run-time dependency flexiblas found: YES 3.4.2

Jetzt können wir die Tests ausführen. Beachten Sie, dass die Option NETLIB ohne Angabe kompiliert wird; sie ist der Standard in FlexiBLAS und die Quellen sind in seinem Repository enthalten.

$ FLEXIBLAS=OpenBLAS python dev.py test -s linalg
$ FLEXIBLAS=NETLIB python dev.py test -s linalg
$ python dev.py test -s linalg  # uses the default (NETLIB)

Dieser Backend-Wechsel kann auch innerhalb eines Python-Interpreters mit threadpoolctl durchgeführt werden (siehe seine README für Details).

Andere auf dem System verfügbare Bibliotheken können mit folgendem inspiziert werden:

$ ./flexiblas-setup/built-libs/bin/flexiblas list

Hinweis

Die Verwendung lokaler Builds von Referenz-BLAS/LAPACK oder BLIS ist schwieriger, da FlexiBLAS eine einzelne Shared-Bibliothek benötigt, die alle erforderlichen Symbole enthält. Es kann machbar sein, eine separate libblas und liblapack als "Systembibliothek" zu verwenden, aber dies hat sich als fragiler und schwieriger zu kompilieren erwiesen (daher YMMV). Falls Sie es dennoch versuchen möchten:

Referenz BLAS und LAPACK kompilieren

$ git clone Reference-LAPACK/lapack.git $ cd lapack $ mkdir build && cd build $ cmake -DCBLAS=ON -DBUILD_SHARED_LIBS=OFF .. $ cmake –build . -j $ cmake –install . –prefix $PWD/../../built-libs

Fügen Sie dann die folgenden beiden Zeilen zur cmake .. Konfigurationsbefehlszeile für FlexiBLAS hinzu.

-DSYS_BLAS_LIBRARY=$PWD/../../built-libs/lib/libblas.a \
-DSYS_LAPACK_LIBRARY=$PWD/../../built-libs/lib/liblapack.a \

Erstellen von Reproduzierern in C oder Fortran#

Unsere Erfahrung zeigt, dass die überwiegende Mehrheit der Fehler in SciPy und nicht in OpenBLAS oder einer anderen BLAS-Bibliothek liegt. Wenn das Testen mit verschiedenen BLAS-Bibliotheken uns jedoch zeigt, dass das Problem spezifisch für eine einzelne BLAS-Bibliothek ist (vielleicht sogar eine einzelne Version dieser Bibliothek mit einer Regression), besteht der nächste Schritt darin, einen Reproduzierer in C oder Fortran zu erstellen. Dies ist notwendig, um den Fehler upstream zu melden, und erleichtert den Entwicklern der BLAS-Bibliothek die Behebung des Problems erheblich.

Um von einem Python-Reproduzierer, der eine scipy-Funktion mit NumPy-Arrays als Eingabe verwendet, zu einem C/Fortran-Reproduzierer zu gelangen, ist es notwendig, den in SciPy genommenen Code-Pfad zu finden und zu bestimmen, welche genaue BLAS- oder LAPACK-Funktion mit welchen Eingaben aufgerufen wird (Hinweis: Die Antwort kann in den .pyf.src f2py-Signaturdateien enthalten sein; ein Blick in das generierte _flapackmodule.c im Build-Verzeichnis kann ebenfalls nützlich sein). Dies kann dann in C/Fortran reproduziert werden, indem einige Integer/Float-Variablen und Arrays definiert werden (typischerweise reichen kleine Arrays mit fest codierten Zahlen aus).

Argumentlisten von BLAS- und LAPACK-Funktionen können z. B. in den Netlib LAPACK-Dokumenten oder im Reference-LAPACK/lapack-Repository nachgeschlagen werden.

Unten ist ein Reproduzierer für ein Problem in Referenz-LAPACK gezeigt, das als SciPy-Problem in scipy#11577 gemeldet wurde. Wir nennen die Datei ggev_repro_gh_11577.c|f90.

#include <stdio.h>
#include "lapacke.h"

#define n 4

int main()
{
    int lda=n, ldb=n, ldvr=n, ldvl=n, info;
    char jobvl='V', jobvr='V';
    double alphar[n], alphai[n], beta[n];

    double vl[n*n], vr[n*n];
    // int lwork = 156;
    // double work[156];    /* cheat: 156 is the optimal lwork from the actual lapack call*/

    double a[n*n] = {12.0, 28.0, 76.0, 220.0,
                     16.0, 32.0, 80.0, 224.0,
                     24.0, 40.0, 88.0, 232.0,
                     40.0, 56.0, 104.0, 248.0};

    double b[n*n] = {2.0, 4.0, 10.0, 28.0,
                     3.0, 5.0, 11.0, 29.0,
                     5.0, 7.0, 13.0, 31.0,
                     9.0, 11.0, 17.0, 35.0};

    info = LAPACKE_dggev(LAPACK_ROW_MAJOR, jobvl, jobvr, n, a, lda, b,
                         ldb, alphar, alphai, beta, vl, ldvl, vr, ldvr); //, work, lwork, info);

    printf("info = %d\n", info);

    printf("Re(eigv) = ");
    for(int i=0; i < n; i++){
        printf("%f , ", alphar[i] / beta[i] );
    }
    printf("\nIm(eigv = ");
    for(int i=0; i < n; i++){
        printf("%f , ", alphai[i] / beta[i] );
    }
    printf("\n");
}
!A = numpy.array([[12.0, 28.0, 76.0, 220.0], [16.0, 32.0, 80.0, 224.0], [24.0, 40.0, 88.0, 232.0], [40.0, 56.0, 104.0, 248.0]], dtype='float64')
! B = numpy.array([[2.0, 4.0, 10.0, 28.0], [3.0, 5.0, 11.0, 29.0], [5.0, 7.0, 13.0, 31.0], [9.0, 11.0, 17.0, 35.0]], dtype='float64')
! D, V = scipy.linalg.eig(A, B); D 
implicit none
integer, parameter :: n = 4

integer :: lda, ldb, ldvr, ldvl, lwork, info
character*1 :: jobvl, jobvr
real*8 :: alphar(n)
real*8 :: alphai(n)
real*8 :: beta(n)
real*8 :: vl(n, n)
real*8 :: vr(n, n)
real*8, allocatable :: work(:)


real*8 :: a(n, n)
real*8 :: b(n, n)

a(1, :) = (/12.0, 28.0, 76.0, 220.0/)
a(2, :) = (/16.0, 32.0, 80.0, 224.0/)
a(3, :) = (/24.0, 40.0, 88.0, 232.0/)
a(4, :) = (/40.0, 56.0, 104.0, 248.0/)

b(1, :) = (/2.0, 4.0, 10.0, 28.0/)
b(2, :) = (/3.0, 5.0, 11.0, 29.0/)
b(3, :) = (/5.0, 7.0, 13.0, 31.0/)
b(4, :) = (/9.0, 11.0, 17.0, 35.0/)

lda = n
ldb = n
ldvr = n
ldvl = n
jobvr = 'V'
jobvl = 'V'

! workspace query

allocate(work(1:8*n)) ! min value
lwork = -1

print*, 'workspace query: lwork = ', lwork

call dggev(jobvl, jobvr, n, a, lda, b, ldb, alphar, alphai, beta, vl, ldvl, vr, ldvr, work, lwork, info)

print*, 'info = ', info
lwork = int(work(1))
print*, 'opt lwork =', lwork

! do the work

deallocate(work)
allocate(work(1:lwork))

call dggev(jobvl, jobvr, n, a, lda, b, ldb, alphar, alphai, beta, vl, ldvl, vr, ldvr, work, lwork, info)

print*
print*, 'info = ', info
print*, 'alphar = ', alphar
print*, 'alphai = ', alphai
print*, 'beta = ', beta
print*
print*, 'Re(eigv) = ', alphar / beta
print*, 'Im(eigv) = ', alphai / beta

deallocate(work)
end

Nun müssen wir diesen Reproduzierer lokal kompilieren und ausführen. Wenn wir einen Compiler direkt aufrufen, müssen wir die benötigten Kompilierungs- und Link-Flags von Hand hinzufügen. Der Include-Pfad hängt von Ihrer lokalen Installation ab, und die Link-Flags hängen davon ab, welche Bibliothek Sie testen. Um z.B. gegen einen lokalen Build von OpenBLAS zu testen:

$ gcc ggev_repro_gh_11577.c \
  -I$PWD/../flexiblas-setup/built-libs/include/ \
  -L$PWD/../flexiblas-setup/built-libs/lib -lopenblas
$ ./a.out  # to run the reproducer
$ gfortran ggev_repro_gh_11577.f90 \
  -I/$PWD/../flexiblas-setup/built-libs/include/ \
  -L$PWD/../flexiblas-setup/built-libs/lib -lopenblas
$ ./a.out  # to run the reproducer

Für Referenz-BLAS/LAPACK sollte -lopenblas durch -lblas -llapack ersetzt werden.

Beachten Sie, dass die expliziten Pfade nur für Bibliotheken an nicht standardmäßigen Orten benötigt werden (wie die, die wir in diesem Leitfaden erstellt haben). Für das Kompilieren gegen eine vom Paketmanager installierte Bibliothek, deren Shared-Bibliothek und Header im normalen Compiler-Suchpfad liegen (z. B. in /usr/lib und /usr/include oder innerhalb einer Conda-Umgebung bei Verwendung von Compilern aus derselben Umgebung), können sie weggelassen werden.

$ gcc ggev_repro_gh_11577.c -lopenblas
$ ./a.out  # to run the reproducer
$ gfortran ggev_repro_gh_11577.f90 -lopenblas
$ ./a.out  # to run the reproducer

Alternativ (und wahrscheinlich robuster) verwenden Sie eine kleine meson.build-Datei, um dies zu automatisieren und die manuellen Pfade zu vermeiden.

project('repro_gh_11577', 'c')

openblas_dep = dependency('openblas')

executable('repro_c',
    'ggev_repro_gh_11577.c',
    dependencies: openblas_dep
)

Um dann den Test zu kompilieren und auszuführen:

$ export PKG_CONFIG_PATH=~/code/tmp/flexiblas-setup/built-libs/lib/pkgconfig/
$ meson setup build
$ ninja -C build
$ ./build/repro_c  # output may vary

info = 0
Re(eigv) = 4.000000 , 8.000000 , inf , -inf ,
Im(eigv = 0.000000 , 0.000000 , -nan , -nan ,
project('repro_gh_11577', 'fortran')

openblas_dep = dependency('openblas')

executable('repro_f90',
    'ggev_repro_gh_11577.f90',
    dependencies: openblas_dep
)

Um dann den Test zu kompilieren und auszuführen:

$ export PKG_CONFIG_PATH=~/code/tmp/flexiblas-setup/built-libs/lib/pkgconfig/
$ meson setup build
$ ninja -C build
$ ./build/repro_f90  # output may vary

workspace query: lwork =           -1
info =            0
opt lwork =         156

info =            0
alphar =    1.0204501477442456        11.707793036240817        3.7423579363517347E-014  -1.1492523608519701E-014
alphai =    0.0000000000000000        0.0000000000000000        0.0000000000000000        0.0000000000000000
beta =   0.25511253693606051        1.4634741295300704        0.0000000000000000        0.0000000000000000

Re(eigv) =    4.0000000000000142        8.0000000000001741                       Infinity                 -Infinity
Im(eigv) =    0.0000000000000000        0.0000000000000000                            NaN                       NaN

Warnung

Wenn Sie mehrere Versionen/Builds derselben BLAS-Bibliothek auf Ihrem Computer haben, ist es leicht, versehentlich die falsche beim Kompilieren zu erwischen (denken Sie daran: -lopenblas bedeutet nur "linke gegen *irgendeine* libopenblas.so"). Wenn Sie sich nicht sicher sind, verwenden Sie ldd für die kompilierte Test-Executable, um zu überprüfen, gegen welche Shared-Bibliothek sie verlinkt ist.

Fehlerbehebung bei Linalg-Problemen mit gdb#

Bei der Fehlerbehebung von Linalg-Problemen kann es manchmal hilfreich sein, sowohl durch Python- als auch durch C-Code zu steppen. Sie können pdb für ersteres und gdb für letzteres verwenden.

Bereiten Sie zunächst einen kleinen Python-Reproduzierer mit einem Haltepunkt vor. Zum Beispiel:

$ cat chol.py
import numpy as np
from scipy import linalg
n = 40
rng = np.random.default_rng(1234)
x = rng.uniform(size=n)
a = x[:, None] @ x[None, :] + np.identity(n)

breakpoint()      # note a breakpoint
linalg.cholesky(a)

Dann müssen Sie ihn unter gdb ausführen und einen Haltepunkt auf C-Ebene bei der LAPACK-Funktion setzen. Auf diese Weise stoppt Ihre Ausführung zweimal: zuerst am Python-Haltepunkt und dann am C-Haltepunkt, und Sie können durchschreiten und die Werte von Python- und C-Variablen inspizieren.

Um den LAPACK-Namen herauszufinden, lesen Sie den Python-Quellcode der SciPy-Funktion und verwenden Sie nm auf der .so-Bibliothek, um den genauen Namen herauszufinden. Für die obige Cholesky-Zerlegung ist die LAPACK-Funktion ?potrf, und der C-Name unter Ubuntu Linux ist dpotrf_ (er kann mit oder ohne nachgestelltem Unterstrich, in Groß- oder Kleinschreibung geschrieben sein, je nach System).

Hier ist ein Beispiel für eine gdb-Sitzung:

$ gdb --args python chol.py
...
(gdb) b dpotrf_     # this adds a C breakpoint (type "y" below)
Function "dpotrf_" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (dpotrf_) pending.
(gdb) run    # run the python script
...
> /home/br/temp/chol/chol.py(12)<module>()
-> linalg.cholesky(a)   # execution stopped at the python breakpoint
(Pdb) p a.shape  # ... inspect the python state here
(40, 40)
(Pdb) c     # continue execution until the C breakpoint

Thread 1 "python" hit Breakpoint 1, 0x00007ffff4c48820 in dpotrf_ ()
   from /home/br/miniforge/envs/scipy-dev/lib/python3.10/site-packages/numpy/core/../../../../libcblas.so.3
(gdb) s     # step through the C function
Single stepping until exit from function dpotrf_,
which has no line number information.
f2py_rout__flapack_dpotrf (capi_self=<optimized out>, capi_args=<optimized out>,
    capi_keywds=<optimized out>, f2py_func=0x7ffff4c48820 <dpotrf_>)
    at scipy/linalg/_flapackmodule.c:63281
....
(gdb) p lda    # inspect values of C variables
$1 = 40

# print out the C backtrace
(gdb) bt
#0  0x00007ffff3056b1e in f2py_rout.flapack_dpotrf ()
   from /path/to/site-packages/scipy/linalg/_flapack.cpython-311-x86_64-linux-gnu.so
#1  0x0000555555734323 in _PyObject_MakeTpCall (tstate=0x555555ad0558 <_PyRuntime+166328>,
    callable=<fortran at remote 0x7ffff40ffc00>, args=<optimized out>, nargs=1,
    keywords=('lower', 'overwrite_a', 'clean'))
    at /usr/local/src/conda/python-3.11.8/Objects/call.c:214
...

Je nach System müssen Sie SciPy möglicherweise mit Debug-Build-Typ kompilieren und CFLAGS/CXXFLAGS-Umgebungsvariablen entkommentieren. Weitere Details finden Sie im NumPy Debugging Guide.

vorherige

SciPy-Tests lokal ausführen

nächste

Beitrag zur SciPy-Dokumentation

Auf dieser Seite
  • Finden der verwendeten BLAS-Bibliothek
  • Einrichtung Ihrer Umgebung zum Wechseln von BLAS-Bibliotheken
    • Conda-forge
    • Linux-Distributionen Paketmanager
    • FlexiBLAS
  • Erstellen von Reproduzierern in C oder Fortran
  • Fehlerbehebung bei Linalg-Problemen mit gdb

© Copyright 2008, Die SciPy-Community.

Erstellt mit Sphinx 8.1.3.

Gebaut mit dem PyData Sphinx Theme 0.16.1.