graph prolog transitive-closure

graph - Definir gráfico en Prolog: borde y camino, encontrando si hay un camino entre dos vértices



transitive-closure (4)

Soy muy nuevo en Prolog. graph.pl en graph.pl el siguiente gráfico:

Y aquí está mi código de Prolog:

edge(a,e). edge(e,d). edge(d,c). edge(c,b). edge(b,a). edge(d,a). edge(e,c). edge(f,b). path(X,X). path(X,Y):- edge(X,Z) ; path(Z,Y).

Lo entiendo así: hay un camino entre el vértice X y el vértice Y solo si hay un borde entre el vértice X y el vértice Z Y hay una ruta entre el vértice Z y el vértice Y (algún tipo de recursión).

¿Es correcto para el gráfico presentado? Cuando le pregunto a Prolog sobre el camino entre el vértice A y el vértice F , me da la true ... ¡que ni siquiera está bien! ¿Qué podría estar mal en este código?


¡Está revisando un ciclo! Ejecuté el ejemplo con el trace. comando previo, y vio, que el programa vuelve al problema para encontrar el camino de a a f después de completar el ciclo. ruta (a, f) necesita que la ruta (e, f) sea verdadera, siguiendo en notación corta necesitamos ser verdaderos:

(d, f), (c, f), (b, f), y luego (a, f) nuevamente.

Para resolver el ciclo, necesitas un mecanismo para evitar el ciclo. Mi primera Idea sería mantener una lista de nombres de nodo y también verificar, si la lista no incluye la X actual mientras verifica la ruta.


Ciclos en el gráfico. Debe rastrear qué nodos está visitando y verificarlos. Pruebe esto, usando un predicado auxiliar con un acumulador para rastrear los nodos visitados:

path(A,B) :- % two nodes are connected, if walk(A,B,[]) % - if we can walk from one to the other, . % first seeding the visited list with the empty list walk(A,B,V) :- % we can walk from A to B... edge(A,X) , % - if A is connected to X, and not(member(X,V)) , % - we haven''t yet visited X, and ( % - either B = X % - X is the desired destination ; % OR walk(X,B,[A|V]) % - we can get to it from X ) % . % Easy! edge(a,e). edge(e,d). edge(d,c). edge(c,b). edge(b,a). edge(d,a). edge(e,c). edge(f,b).


El formato que usa (edge ​​/ 2) tiene sentido para aprender sobre Prolog, y debe seguir los consejos de mbratch sobre el tutorial.

En realidad, ya hay buenas alternativas disponibles, en algunos casos con predicados útiles listos para funcionar: por ejemplo, en la biblioteca ( ugraph ), se puede alcanzar / 3. Ahora, con sus datos, este predicado de ruta / 2

path(X,Y) :- findall(A-B, edge(A,B), Es), vertices_edges_to_ugraph([],Es,G), reachable(X,G,Path), member(Y,Path).

hace

?- path(a,X). X = a ; X = b ; X = c ; X = d ; X = e.

Veamos lo que significa:

findall(A-B, edge(A,B), Es)

poner en Es todos los bordes, con notación según lo requiera la biblioteca,

vertices_edges_to_ugraph([],Es,G)

construye en G el gráfico correspondiente

reachable(X,G,Path)

hacer una lista Ruta de todos los vértices accesibles (duh) desde X

member(Y,Path)

ver si Y está presente en Path.

Como realicé consultas con Y free , obtengo todos los vértices alcanzables de X, que ligé a a .


Si está interesado en saber si existe una ruta, pero no necesariamente en la (s) ruta (s) real (es), investigue el cierre transitivo de la relación binaria edge/2 .

Afortunadamente para ti, el cierre transitivo es una expresión común en Prolog .

Para expresar el cierre transitivo irreflexivo de edge/2 , use meta-predicate closure/3 -definido en la pregunta anterior " Definition of Reflexive Transitive Closure ":

?- closure(edge, X, Y). X = a, Y = e ; X = a, Y = d ; X = a, Y = c ; ...

Tenga en cuenta que el closure/3 tiene muy buenas propiedades de terminación.

Si todas las cláusulas de edge/2 son datos closure(edge, _, _) , ¡el closure(edge, _, _) termina universalmente! Mira:

?- closure(edge, _, _), false. false.