¿Existe un equivalente de Python a la desreferenciación en Perl?
numpy reference (1)
Actualmente estoy portando una base de código, que implementé inicialmente en Perl, a Python. El siguiente fragmento corto de código ocupa aproximadamente el 90% del tiempo de ejecución significativo cuando ejecuto todo el conjunto de datos.
def equate():
for i in range(row):
for j in range(row):
if adj_matrix[i][j] != adj_matrix[mapping[i]][mapping[j]]:
return False
return True
Donde equate es un cierre dentro de otro método, row es un entero, adj_matrix es una lista de listas que representa una matriz y mapping es una lista que representa un vector.
El código Perl equivalente es el siguiente:
sub equate
{
for ( 0..$row)
{
my ($smrow, $omrow) = ($$adj_matrix[$_], $$adj_matrix[$$mapping[$_]]); #DEREF LINE
for (0..$row)
{
return 0 if $$smrow[$_] != $$omrow[$$mapping[$_]];
}
}
return 1;
}
Esto está encapsulado como una sub ref en la subrutina externa, por lo que no tengo que pasar variables a la subrutina.
En resumen, la versión de Perl es mucho más rápida y mis pruebas indican que se debe a la eliminación de referencias en "DEREF LINE". Intenté lo que creía que era el equivalente en Python:
def equate():
for i in range(row):
row1 = adj_matrix[i]
row2 = adj_matrix[mapping[i]]
for j in range(row):
if row1[j] != row2[mapping[j]]:
return False
return True
Pero esta fue una mejora insignificante. Además, traté de usar una matriz NumPy para representar adj_matrix, pero de nuevo, esta fue una pequeña mejora, probablemente porque adj_matrix suele ser una pequeña matriz, por lo que la sobrecarga de NumPy es mucho mayor, y realmente no estoy haciendo ninguna operación matemática matricial.
Agradezco cualquier sugerencia para mejorar el tiempo de ejecución del método Python equate
y una explicación de por qué mi método "mejorado" Python equate
no es mucho mejor. Si bien me considero un programador de Perl competente, soy un principiante de Python.
DETALLES ADICIONALES:
Estoy usando Python 3.4, aunque se observó un comportamiento similar cuando inicialmente lo implementé en 2.7. Cambié a 3.4 ya que el laboratorio en el que trabajo utiliza 3.4.
En cuanto a los contenidos de los vectores, permítanme proporcionar algunos antecedentes para que los siguientes detalles tengan sentido. Esto es parte de un algoritmo para identificar subomorfismos entre dos compuestos químicos (a y b) representados por los gráficos A y B, respectivamente, donde cada átomo es un nodo y cada enlace un borde. El código anterior es para el caso simplificado donde A = B, entonces estoy buscando transformaciones simétricas del compuesto (planos de simetría), y el tamaño de A en número de átomos es N. A cada átomo se le asigna un índice único que comienza en cero.
El mapeo es un vector 1D de dimensiones 1xN donde cada elemento en un mapeo es un número entero. mapping[i] = j
, representa que el átomo con índice i (se referirá como átomo i o genéricamente átomo ''índice'') está actualmente asignado al átomo j. La ausencia de un mapeo se indica con j = -1.
Adj_matrix es una matriz 2D de dimensiones NxN donde cada elemento adj_matrix [i] [j] = k es un número natural y representa la presencia y el orden de un borde entre los átomos i y j en el compuesto A. Si k = 0, no hay dicho borde (AKA no bond entre i y j) sino k> 0 yk representa el orden del enlace entre los átomos i y j.
Cuando A! = B, hay dos adj_matrices diferentes que se comparan en equate y el tamaño de a y b en átomos es Na y Nb. Na no tiene que ser igual a Nb, pero Na = <Nb. Solo menciono esto ya que las optimizaciones son posibles para el caso especial que no son válidas en el caso general, pero cualquier consejo sería útil.
Con Numpy puedes vectorizar todo tu código de la siguiente manera, suponiendo que adj_matrix
y mapping
son matrices numpy:
def equate():
row1 = adj_matrix[:row]
row2 = adj_matrix[mapping[:row]]
return np.all(row1 == row2)
No se inicia al principio del ciclo si encuentra una discrepancia, pero a menos que tus matrices sean enormes, la velocidad de NumPy va a dominar.