Nuestro equipo programó una función de R que realiza el algoritmo de Floyd para hallar las rutas más cortas en una red.
Código R
El código se muestra a continuación:
FloydRapido<-function(A){
# Esto es para instalar paquetes nadamás:
if(!"dplyr"%in%rownames(installed.packages())){
install.packages("dplyr")
}
require(dplyr)
# Extraemos el número de nodos de la red:
n<-ncol(A)
# Construimos la matriz C para iterar:
C<-A
C[C==0]<-Inf;diag(C)<-0
# Definimos la matriz Z de recuperación de rutas:
Z<-1:n;Z<-rep(Z,n)
Z<-matrix(Z,ncol = n)
# Definimos la variable que indica si el proceso terminó
# en las n iteraciones o antes.
exited<-FALSE
# Un nodo que está en un circuito de longitud negativa:
neg.length<-NULL
# Corremos las n iteraciones que exige el algoritmo.
for(i in 1:n){
# Aquí sólo estamos extrayendo los índices de los
# elementos de la columna i distintos de infinito e i.
Reng<-C[,i]%>%is.finite%>%which
Reng<-Reng[Reng%>%(function(x) x!=i)%>%which] %>% unname()
# Misma cosa sólu que con los índices del renglón i.
Colu<-C[i,]%>%is.finite%>%which
Colu<-Colu[Colu%>%(function(x) x!=i)%>%which] %>% unname()
if(length(Colu)>0&length(Reng)>0){
# AUX es una matriz auxiliar que tiene las entradas
# por analizar.
AUX<-C[Reng,Colu] %>% unname() %>% matrix(nrow=length(Reng),ncol=length(Colu))
# Sumas contiene las C_{ki}+C_{il}
Sumas<-outer(C[Reng,i],C[i,Colu],FUN = function(x,y)x+y) %>% unname()
# Comparamos entrada a entrada ambas matrices y
# actualizamos las entradas de C que haya que
# actualizar.
C[Reng,Colu]<-pmin(Sumas,AUX)
# Si hubo cambio se actualizan las entradas correspondientes
# de Z.
Z[Reng,Colu]<-Z[Reng,Colu]*(Sumas>=AUX)+Z[rep(i,length(Reng)),Colu]*(Sumas<AUX)
# Revisamos que no haya negativos en la diagonal:
if(any(diag(C)<0)){
exited<-TRUE
neg.length<-C%>%diag%>%(function(x) which(x<0))
break()
}
}else{
next()
}
}
# Juntamos las matrices de distancias y recuperación de
# rutas finales, el estatus de salida, el # de iteraciones
# y el nodo en el C de long. negativa si lo hay.
respuesta<-list(
C=C,
Z=Z,
exited=exited,
neg.length=neg.length,
iter=i
)
# Regresamos la lista con las salidas deseadas.
return(respuesta)
}
Correr con un ejemplo
Vamos a descomponer en pasos y correr sobre una red concreta.
Considere la siguiente red:
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 0 1 0 0 0 0 0 0 0
## [2,] 0 0 1 0 0 1 0 0 0
## [3,] 0 0 0 0 0 0 0 0 0
## [4,] 0 0 0 0 0 0 0 0 0
## [5,] 0 0 0 1 0 0 1 1 0
## [6,] 0 0 0 0 1 0 0 0 1
## [7,] 0 0 0 0 0 0 0 0 0
## [8,] 0 0 0 0 0 0 0 0 0
## [9,] 0 0 0 0 0 0 0 0 0
Paso 1
Definir la C y Z iniciales.
if (!"dplyr" %in% rownames(installed.packages())) {
install.packages("dplyr")
}
require(dplyr)
n <- ncol(A)
C <- A
C[C == 0] <- Inf
diag(C) <- 0
Z <- 1:n
Z <- rep(Z, n)
Z <- matrix(Z, ncol = n)
exited <- FALSE
neg.length <- NULL
C;Z
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 0 1 Inf Inf Inf Inf Inf Inf Inf
## [2,] Inf 0 1 Inf Inf 1 Inf Inf Inf
## [3,] Inf Inf 0 Inf Inf Inf Inf Inf Inf
## [4,] Inf Inf Inf 0 Inf Inf Inf Inf Inf
## [5,] Inf Inf Inf 1 0 Inf 1 1 Inf
## [6,] Inf Inf Inf Inf 1 0 Inf Inf 1
## [7,] Inf Inf Inf Inf Inf Inf 0 Inf Inf
## [8,] Inf Inf Inf Inf Inf Inf Inf 0 Inf
## [9,] Inf Inf Inf Inf Inf Inf Inf Inf 0
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 1 1 1 1 1 1 1 1 1
## [2,] 2 2 2 2 2 2 2 2 2
## [3,] 3 3 3 3 3 3 3 3 3
## [4,] 4 4 4 4 4 4 4 4 4
## [5,] 5 5 5 5 5 5 5 5 5
## [6,] 6 6 6 6 6 6 6 6 6
## [7,] 7 7 7 7 7 7 7 7 7
## [8,] 8 8 8 8 8 8 8 8 8
## [9,] 9 9 9 9 9 9 9 9 9
Paso 2
Correr las n iteraciones, aquí sólo haremos la segunda para convencernos de que el algoritmo hace lo que se quiere.
La matriz C tras la primera iteración es:
C
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 0 1 Inf Inf Inf Inf Inf Inf Inf
## [2,] Inf 0 1 Inf Inf 1 Inf Inf Inf
## [3,] Inf Inf 0 Inf Inf Inf Inf Inf Inf
## [4,] Inf Inf Inf 0 Inf Inf Inf Inf Inf
## [5,] Inf Inf Inf 1 0 Inf 1 1 Inf
## [6,] Inf Inf Inf Inf 1 0 Inf Inf 1
## [7,] Inf Inf Inf Inf Inf Inf 0 Inf Inf
## [8,] Inf Inf Inf Inf Inf Inf Inf 0 Inf
## [9,] Inf Inf Inf Inf Inf Inf Inf Inf 0
Comenzamos la iteración 2.
i<-2
# Aquí sólo estamos extrayendo los índices de los
# elementos de la columna i distintos de infinito e i.
Reng<-C[,i]%>%is.finite%>%which
Reng<-Reng[Reng%>%(function(x) x!=i)%>%which] %>% unname()
Reng
## [1] 1
# Misma cosa sólu que con los índices del renglón i.
Colu<-C[i,]%>%is.finite%>%which
Colu<-Colu[Colu%>%(function(x) x!=i)%>%which] %>% unname()
Colu
## [1] 3 6
# Condición para ver si podemos modificar algo:
length(Colu)>0&length(Reng)>0
## [1] TRUE
if(length(Colu)>0&length(Reng)>0){
# AUX es una matriz auxiliar que tiene las entradas
# por analizar.
AUX<-C[Reng,Colu] %>% unname() %>%
matrix(nrow=length(Reng),ncol=length(Colu))
# Sumas contiene las C_{ki}+C_{il}
Sumas<-outer(C[Reng,i],C[i,Colu],FUN = function(x,y)x+y) %>% unname()
# Comparamos entrada a entrada ambas matrices y
# actualizamos las entradas de C que haya que
# actualizar.
C[Reng,Colu]<-pmin(Sumas,AUX)
# Si hubo cambio se actualizan las entradas correspondientes
# de Z.
Z[Reng,Colu]<-Z[Reng,Colu]*(Sumas>=AUX)+Z[rep(i,length(Reng)),Colu]*(Sumas<AUX)
# Revisamos que no haya negativos en la diagonal:
if(any(diag(C)<0)){
exited<-TRUE
neg.length<-C%>%diag%>%(function(x) which(x<0))
# break()
}
}else{
# next()
}
AUX;Sumas
## [,1] [,2]
## [1,] Inf Inf
## [,1] [,2]
## [1,] 2 2
C;Z
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 0 1 2 Inf Inf 2 Inf Inf Inf
## [2,] Inf 0 1 Inf Inf 1 Inf Inf Inf
## [3,] Inf Inf 0 Inf Inf Inf Inf Inf Inf
## [4,] Inf Inf Inf 0 Inf Inf Inf Inf Inf
## [5,] Inf Inf Inf 1 0 Inf 1 1 Inf
## [6,] Inf Inf Inf Inf 1 0 Inf Inf 1
## [7,] Inf Inf Inf Inf Inf Inf 0 Inf Inf
## [8,] Inf Inf Inf Inf Inf Inf Inf 0 Inf
## [9,] Inf Inf Inf Inf Inf Inf Inf Inf 0
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 1 1 2 1 1 2 1 1 1
## [2,] 2 2 2 2 2 2 2 2 2
## [3,] 3 3 3 3 3 3 3 3 3
## [4,] 4 4 4 4 4 4 4 4 4
## [5,] 5 5 5 5 5 5 5 5 5
## [6,] 6 6 6 6 6 6 6 6 6
## [7,] 7 7 7 7 7 7 7 7 7
## [8,] 8 8 8 8 8 8 8 8 8
## [9,] 9 9 9 9 9 9 9 9 9
Resultado
FloydRapido(A)$C
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 0 1 2 4 3 2 4 4 3
## [2,] Inf 0 1 3 2 1 3 3 2
## [3,] Inf Inf 0 Inf Inf Inf Inf Inf Inf
## [4,] Inf Inf Inf 0 Inf Inf Inf Inf Inf
## [5,] Inf Inf Inf 1 0 Inf 1 1 Inf
## [6,] Inf Inf Inf 2 1 0 2 2 1
## [7,] Inf Inf Inf Inf Inf Inf 0 Inf Inf
## [8,] Inf Inf Inf Inf Inf Inf Inf 0 Inf
## [9,] Inf Inf Inf Inf Inf Inf Inf Inf 0
FloydRapido(A)$C %>% lattice::levelplot()
FloydRapido(A)$C %>% graph_from_adjacency_matrix() %>%
plot(edge.arrow.size=0.4)