definir una firma numposa para la matriz de salida de longitud desconocida (para uso en numba.guvectorize)

Es posible crear una firma para un numpy ufunc que devuelve una matriz de 1d de longitud desconocida?

Tengo una función que toma en un array x de longitud (n) y una matriz de etiquetas y de longitud (m), realiza una reducción y devuelve el array out de tamaño desconocido.

La función misma se envuelve con numba.guvectorize:

@guvectorize([(int16[:], float64[:], int32[:], int16[:])], "(n),(m) -> (l)", nopython=True)
def fun(x, y, out):
    #perform stuff
    # ...
    # no return in guvectorize

Esto devuelve el siguiente error:

NameError: símbolos de salida no definidos: l

Mi solución sería pasar en un conjunto de plantillas de longitud lPero no se usaría para ningún cálculo, así que me gustaría evitarlo.

¿Alguna manera alrededor de esto, o está pasando en una plantilla la mejor (y tal vez no tan mala) solución?

Editar:

Algunos puntos válidos hechos en los comentarios que quiero abordar:

Se supone que la función se aplique en un array con dimensiones (x, y, z) a lo largo z dimensión, que tiene longitud n.

El propósito previsto de la función es tomar cada matriz 1d a lo largo de z

[z,z,z,z,z,z,z,z,...,z]

y ampliarlo a la longitud m

[z1,z1,z1,z2,z2,z2,z2,z3,...,zz]

y finalmente los valores correspondientes se promedian

[z1,z2,z3,z4,z5,z6,z7,z8,...,zz]

resultante en un array con longitud l.

Sé de antemano exactamente qué tamaños m, n y l será - solo necesito "tell" a la función. Es por eso que tampoco espero salidas.

La manera más rápida de aplicar esto a un gran array 3d usando xarray está con guvectorize. Pero esto resulta en la cuestión anterior.

Una solución de trabajo es pasar en una plantilla de longitud l.

Para comparación, he creado un @njit función envuelta, que manualmente bucles sobre la primera dos dimensiones, aplicando la misma funcionalidad.

Desafortunadamente esto sigue siendo aproximadamente 4 veces más lento que el uso guvectorizeAsí que me gustaría usar guvectorize para esta aplicación.

Pregunta hecha hace 3 años, 4 meses, 28 días - Por rubyrogue


2 Respuestas:

  • Para definir una firma numposa para la matriz de salida de longitud desconocida en numba.guvectorize, puedes utilizar una firma numposa l->() en lugar de "(n),(m) -> (l)". Esto indica que la longitud de la matriz de salida es desconocida y será determinada durante la ejecución de la función.

    Aquí tienes un ejemplo de cómo podrías ajustar tu decorador guvectorize:

    python
    from numba import guvectorize, float64, int32, int16
    
    @guvectorize([(int16[:], float64[:], int32[:])], "(),() -> ()", nopython=True)
    def fun(x, y, out):
        

    Realiza la reducción y asigna el resultado a 'out'

    out[0] = 0

    Aquí se asignaría el resultado de la reducción

    Ejemplo de uso

    x = np.array([1, 2, 3], dtype=np.int16) y = np.array([0.1, 0.2, 0.3], dtype=np.float64) out = np.empty(1, dtype=np.int32) fun(x, y, out) print(out)

    Al especificar la firma numposa (l->()), le estás diciendo a la función guvectorize que la longitud de la matriz de salida se determinará dinámicamente en tiempo de ejecución.

    Espero que esta solución te ayude a resolver el problema que estás experimentando. ¡Déjame saber si tienes alguna otra pregunta!

    Respondida el Dec 18, 2020 a las 10:06 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Sí, es posible crear una firma para un numpy ufunc que devuelve una matriz 1D de longitud desconocida. Aquí hay un ejemplo usando numba.guvectorize:

    python
    import numpy as np
    from numba import guvectorize
    
    @guvectorize([(np.int16[:], np.float64[:], np.int32[:], np.int16[:])], "(n),(m) -> ()", nopython=True)
    def fun(x, y, out):
        

    Realizar cálculos

    ...

    Asignar el resultado a la matriz de salida

    out[()] = resultado

    En esta firma, el tipo de retorno se especifica como () para indicar que no se devuelve ningún valor explícito. En su lugar, el resultado se asigna directamente a la matriz de salida proporcionada por numba.guvectorize.

    Tenga en cuenta que la función fun debe ser pura, es decir, no debe modificar ningún dato de entrada o variable global.

    Ejemplo de uso:

    python
    x = np.array([1, 2, 3], dtype=np.int16)
    y = np.array([0.1, 0.2, 0.3], dtype=np.float64)
    
    

    Crear una matriz de salida con longitud desconocida

    out = np.empty(0, dtype=np.int16)

    Aplicar la función guvectorizada

    fun(x, y, out)

    Imprimir la matriz de salida

    print(out)

    Esto imprimirá el resultado de la función fun como un array 1D, incluso si la longitud del array de salida es desconocida de antemano.

    Respondida el Dec 18, 2020 a las 10:18 - por Gemini

    Votos positivos: 0 | Votos negativos: 0