es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Matriz de distancia en celda unidad (considerando la simetría)

Estoy enfrentando un problema para calcular una matriz de distancia grande. No obstante, esta es una matriz de distancia específica: es una matriz de puntos que están en una celda unitaria. Esta función obtiene coordenadas fraccionarias (entre 0 y 1 en todas las dimensiones) y me gustaría calcular la matriz de distancia teniendo en cuenta el hecho de que hay una copia idéntica del punto en cada vecino de la celda unitaria, y por lo tanto, la distancia correcta puede estar con la copia en lugar del otro punto dentro de la celda unitaria.
¿Sabes si algo se puede hacer con las bibliotecas preprogramadas de scipy o numpy en C para esto? He hecho un código de numba que funciona pero se ejecuta bastante lentamente. Aquí tengo una lista de 13160 puntos para los cuales quiero calcular una matriz de distancia de 13160 * 13160, es decir, que contiene 173185600 elementos.
El principio es: para cada coordenada, calcular la distancia fraccional al cuadrado del primer punto con el segundo punto ya sea dentro de la celda o en uno de sus dos vecinos (atrás y adelante). Luego obtener el mínimo de la distancia al cuadrado para cada coordenada y obtener la distancia euclidiana correspondiente a partir de las coordenadas cartesianas.
El tiempo que tarda actualmente es: 40.82661843299866 segundos.
¿Sabes si puedo hacer que se ejecute más rápido de alguna manera, o es que mi conjunto de datos es simplemente grande y no hay nada más que hacer?
A continuación se muestra el código:

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una posible solución para acelerar su código es hacer uso de la función de transmisión de numpy. Esto eliminaría los bucles for y la necesidad de evaluar el segmento más cercano según la traducción a las celdas vecinas para cada par de puntos. Una forma de lograr esto es creando tres matrices 3D de forma (n_sg, n_sg, 3) correspondientes a las diferencias en las coordenadas x, y y z entre cada par de puntos en las tres direcciones. Estas matrices pueden elevarse al cuadrado y sumarse a lo largo del último eje para obtener las distancias fraccionarias al cuadrado. Luego, se puede obtener el mínimo a lo largo del segundo eje para obtener el cambio correcto en cada dirección. Finalmente, se pueden calcular las distancias euclidianas a partir de las coordenadas cartesianas utilizando las operaciones vectorizadas de numpy.

    Aquí está el código modificado utilizando este enfoque:

    def getDistInCell(fract, xyz, n_sg, a, b, c):
        # calcular las diferencias en las coordenadas x, y y z entre cada par de puntos
        diff = xyz[:, None] - (xyz[None] + np.array([[-1, 0, 1]])[:, None, None] * np.array([[a, b, c]])[None, None, :])
    
        # elevar al cuadrado y sumar a lo largo del último eje para obtener las distancias fraccionarias al cuadrado
        diff_sq = np.square(diff)
        diff_sq_sum = np.sum(diff_sq, axis=-1)
    
        # obtener cambios en las direcciones x, y y z encontrando el mínimo a lo largo del segundo eje
        shift = np.argmin(diff_sq_sum, axis=1) - 1
    
        # calcular distancias cartesianas
        shifted_xyz = xyz[None] + shift[:, None] * np.array([[a, b, c]])[None, :]
        dist = np.sqrt(np.sum(np.square(xyz[:, None] - shifted_xyz), axis=-1))
    
        return dist
    

    Luego, puede llamar a esta función y comparar el tiempo de ejecución con la implementación original:

    import time
    
    # generar algunos datos de muestra
    n_sg = 13160
    fract = np.random.rand(n_sg, 3)
    xyz = np.random.rand(n_sg, 3)
    a, b, c = 1, 1, 1
    
    start_time = time.time()
    dist = getDistInCell(fract, xyz, n_sg, a, b, c)
    end_time = time.time()
    print("Tiempo transcurrido: {:.3f} segundos".format(end_time - start_time))
    

    Esto debería darle una mejora considerable en la velocidad en comparación con la implementación original. Tenga en cuenta que el tiempo de ejecución exacto puede depender del tamaño de sus datos y del hardware que esté utilizando.

Comments are closed.