Cython: „błąd krytyczny: numpy / arrayobject.h: nie ma takiego pliku lub katalogu”

141

Próbuję tu przyspieszyć odpowiedź , używając Cythona. Próbuję skompilować kod (po wykonaniu cygwinccompiler.pywłamania opisanego tutaj ), ale pojawia się fatal error: numpy/arrayobject.h: No such file or directory...compilation terminatedbłąd. Czy ktoś może mi powiedzieć, czy jest to problem z moim kodem, czy jakaś ezoteryczna subtelność w Cythonie?

Poniżej znajduje się mój kod.

import numpy as np
import scipy as sp
cimport numpy as np
cimport cython

cdef inline np.ndarray[np.int, ndim=1] fbincount(np.ndarray[np.int_t, ndim=1] x):
    cdef int m = np.amax(x)+1
    cdef int n = x.size
    cdef unsigned int i
    cdef np.ndarray[np.int_t, ndim=1] c = np.zeros(m, dtype=np.int)

    for i in xrange(n):
        c[<unsigned int>x[i]] += 1

    return c

cdef packed struct Point:
    np.float64_t f0, f1

@cython.boundscheck(False)
def sparsemaker(np.ndarray[np.float_t, ndim=2] X not None,
                np.ndarray[np.float_t, ndim=2] Y not None,
                np.ndarray[np.float_t, ndim=2] Z not None):

    cdef np.ndarray[np.float64_t, ndim=1] counts, factor
    cdef np.ndarray[np.int_t, ndim=1] row, col, repeats
    cdef np.ndarray[Point] indices

    cdef int x_, y_

    _, row = np.unique(X, return_inverse=True); x_ = _.size
    _, col = np.unique(Y, return_inverse=True); y_ = _.size
    indices = np.rec.fromarrays([row,col])
    _, repeats = np.unique(indices, return_inverse=True)
    counts = 1. / fbincount(repeats)
    Z.flat *= counts.take(repeats)

    return sp.sparse.csr_matrix((Z.flat,(row,col)), shape=(x_, y_)).toarray()
Noob Saibot
źródło
czy możesz dodać tag dla jakiego systemu operacyjnego używasz?
tacaswell
@tcaswell 64-bitowy Windows 7.
Noob Saibot
dodał tag windows, mam nadzieję, że pomoże to w zauważeniu tego problemu przez osoby, które wiedzą, jak używać okien (w przeciwieństwie do mnie).
tacaswell
1
Znalazłem to . Część terminologii jest ponad moją głową, ale zamierzam to sprawdzić.
Noob Saibot

Odpowiedzi:

195

W twoim setup.py, Extensionpowinni mieć argument include_dirs=[numpy.get_include()].

Brakuje również np.import_array()twojego kodu.

-

Przykład setup.py:

from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy

setup(
    ext_modules=[
        Extension("my_module", ["my_module.c"],
                  include_dirs=[numpy.get_include()]),
    ],
)

# Or, if you use cythonize() to make the ext_modules list,
# include_dirs can be passed to setup()

setup(
    ext_modules=cythonize("my_module.pyx"),
    include_dirs=[numpy.get_include()]
)    
Robert Kern
źródło
4
Dlaczego miałbym potrzebować np.import_array()? Czy to nie dotyczy Numpy C-API ?
Noob Saibot
Wypróbowałem twój pomysł, ale teraz dostaję ten szalony błąd, który jest zbyt długi, aby go tutaj opublikować, ale zaczyna się odwarning: untitled.pyx:8:49: Buffer unpacking not optimized away.
Noob Saibot
Ach, prawda, prawdopodobnie nie potrzebujesz np.import_array(). Rzadko jednak piszę numpy-using Cython bez niego, więc używam go z przyzwyczajenia. Jeśli chodzi o twój inny problem, to, co zacytowałeś, jest tylko ostrzeżeniem, a nie błędem. Jeśli masz inne błędy, które wymagają naprawy, napisz nowy wpis.
Robert Kern,
1
include_dirs=[numpy.get_include()]to fajna sztuczka, dziękuję!
Daniel Farrell
14
include_dirsprzekazany do setup()zostaje zignorowany w najnowszych dystrybucjach, musi zostać przekazany każdemu Extension, przynajmniej na mac
dashesy
46

W przypadku projektu jednoplikowego, takiego jak Twój, inną alternatywą jest użycie pyximport. Nie musisz tworzyć setup.py... nie musisz nawet otwierać wiersza poleceń, jeśli używasz IPython ... to wszystko jest bardzo wygodne. W twoim przypadku spróbuj uruchomić te polecenia w IPythonie lub w zwykłym skrypcie Python:

import numpy
import pyximport
pyximport.install(setup_args={"script_args":["--compiler=mingw32"],
                              "include_dirs":numpy.get_include()},
                  reload_support=True)

import my_pyx_module

print my_pyx_module.some_function(...)
...

Oczywiście może zajść potrzeba edycji kompilatora. Dzięki temu import i ponowne ładowanie działają tak samo dla .pyxplików, jak dla .pyplików.

Źródło: http://wiki.cython.org/InstallingOnWindows

Steve Byrnes
źródło
Dzięki, @SteveB. Ale czy możesz nieco wyjaśnić, co masz na myśli, mówiąc „ Dla projektu jednoplikowego, takiego jak Twój …”? Powyższy moduł jest jedną (choć ważną) częścią większej aplikacji. Jak pyximportwpływa na szybkość mojego kodu? I wreszcie sekcja tutaj: Od Cythona 0.11, moduł pyximport obsługuje również eksperymentalną kompilację dla zwykłych modułów Pythona …” sugeruje, że nadal ma kilka problemów do rozwiązania. Czy możesz to również wyjaśnić?
Noob Saibot
1
Re „Eksperymentalna obsługa kompilacji dla normalnych modułów Pythona” - z kodem, który zasugerowałem powyżej, .pymoduły są kompilowane normalnie (nie z cythonem), podczas gdy .pyxmoduły są kompilowane z cythonem. Jeśli przejdziesz pyimport = Truedo pyximport.install(), użyje cythonu do wszystkiego, nawet na przykład import randomlub import os. Nie sugeruję korzystania z tej funkcji, po prostu dlatego, że nie ma ważnego powodu, aby z niej korzystać, a może to powodować problemy. Prawdopodobnie jest używany głównie przez programistów cython.
Steve Byrnes
Jeśli pyximportw ogóle zadziała, utworzy dokładnie ten sam kod C, co każda inna metoda. Więc spróbuj i zobacz. Byłem odnosząc się do faktu, że gdy proces kompilacji jest wystarczająco skomplikowane, np linki do zewnętrznych bibliotek systemowych, możesz stwierdzić, że pyximport zawiedzie i trzeba setup.pyi cythonizeokreślić dokładnie, jak go zbudować. Ale fakt, że twój .pyxmoduł ma imports lub cimports, nie oznacza, że ​​nie można go skompilować pyximport; może być całkiem dobrze.
Steve Byrnes
Mam post w Cythonie, na który możesz mieć wgląd.
Phillip,
To działa świetnie! Ale polecam --compiler = msvc, jeśli masz już zainstalowany msvc. Wtedy nie musisz instalować mingw.
Steve
14

Ten błąd oznacza, że ​​plik nagłówkowy numpy nie został znaleziony podczas kompilacji.

Spróbuj zrobić export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/, a następnie skompiluj. Jest to problem z kilkoma różnymi pakietami. W ArchLinux został zgłoszony błąd dotyczący tego samego problemu: https://bugs.archlinux.org/task/22326

John Brodie
źródło
Gdzie dodać exportlinię? W moim setup.pypliku?
Noob Saibot
Nie, to polecenie powłoki. Uruchom go w swojej powłoce, a następnie zacznij kompilować.
John Brodie
@NoobSaibot w powłoce (gdzie uruchamiasz python setup.py) uruchom export ..komendę jako pierwszą. Ustawia zmienne środowiskowe powłoki, a nie ma bezpośredniego związku z [pc] ython.
tacaswell
@tcaswell: Myślałem, że tak dużo. Używam cmd i mam ten 'export' is not recognized as an internal or external command, operable program or batch file.błąd ... po prostu nie mogę wygrać z tym ...
Noob Saibot
4
@NoobSaibot otrzymujesz odpowiedzi LUNIX na to, co pachnie jak problem z systemem Windows ...
tacaswell
1

Prosta odpowiedź

O wiele prostszym sposobem jest dodanie ścieżki do pliku distutils.cfg. Domyślnie jest to nazwa ścieżki systemu Windows 7 C:\Python27\Lib\distutils\. Po prostu potwierdzasz następującą zawartość i powinno się udać:

[build_ext]
include_dirs= C:\Python27\Lib\site-packages\numpy\core\include

Cały plik konfiguracyjny

Aby dać ci przykład, jak mógłby wyglądać plik konfiguracyjny, cały mój plik czyta:

[build]
compiler = mingw32

[build_ext]
include_dirs= C:\Python27\Lib\site-packages\numpy\core\include
compiler = mingw32
strpeter
źródło
1

Powinien być w stanie to zrobić w ramach cythonize()funkcji, jak wspomniano tutaj , ale nie działa, ponieważ występuje znany problem

hsc
źródło
1

Jeśli jesteś zbyt leniwy, aby pisać pliki instalacyjne i znaleźć ścieżkę do katalogów nagłówków , wypróbuj cyper . Może skompilować Twój kod Cythona i include_dirsautomatycznie ustawić Numpy.

Załaduj swój kod do ciągu, a następnie po prostu uruchom cymodule = cyper.inline(code_string), a Twoja funkcja będzie dostępna cymodule.sparsemakernatychmiast. Coś takiego

code = open(your_pyx_file).read()
cymodule = cyper.inline(code)

cymodule.sparsemaker(...)
# do what you want with your function

Możesz zainstalować cypera za pośrednictwem pip install cyper.

Syrtis Major
źródło