Prolog graph representation missing fact - prolog

I have a graph with edges in Prolog. I'm representing the graph as a set of prolog facts. Where e.g. s(a,b,2). = b is the successor of a. Here are my facts in prolog for this graph.
Facts:
s(a,b,2).
s(a,c,1).
s(b,e,4).
s(b,g,2).
s(c,d,1).
s(c,x,3).
s(x,g,1).
goal(g).
Am I missing a fact here? s(e,g,1).
Where g is the successor of e? Or does it even get searched on this node as "b" only has 2 branches "e" & "g". Can someone please explain this to me? Thanks

We can enumerate the graph for example in a breadth-first [Wiki] fashion, and thus determine that the edges are:
s(a, b, 2).
s(a, c, 1).
s(b, e, 4).
s(b, g, 2),
s(c, d, 1).
s(c, x, 3).
s(e, g, 1).
s(x, g, 1).
goal(g).
If we look at the original source code. The s(e, g, 1). part was missing.

Related

How can I code a specific game in Prolog?

I have a problem with coding the program described below
Consider the following game. A board with three black stones, three white stones and an empty space is given. The goal of the game is to swap places of black pawns with white pawns. Moving rules define the following sentences: Move the white and black pieces alternately. Each pawn can move vertically or horizontally taking up an empty space. Each piece can jump vertically or horizontally over another piece (of any color). Write a program in Prolog to find all possible ways to find a winning sequence. For example, if we ask the question:
? - play (w, s (w, w, w, e, b, b, b), s (b, b, b, e, w, w, w), S, R ).
The prologue should answer, for example:
S = [s (w, w, w, e, b, b, b), s (w, e, w, w, b, b, b), ..., s (b, b, b, e, w, w, w)] R = [[w, 2,4], [b, 6,2], [w, 4,6], ..., [w, 4,6]]
Here [ w, 2,4] means moving the white pawn from position 2 to position 4. Of course Prolog should return both letters S and R in full (without "...").
What is the maximum number of different pawn settings possible on the board? Check the query:
? - play (_, s (w, w, w, e, b, b, b), s (b, b, e, w, w, b, w), _, _).
What does Prolog's answer mean? Hint: solve the problem for play/4 without R first
There's also a game board that looks like this:
I have no clue at all even where to start? How can I do that? Could you guys, help me with this one?
This is a standard state space search, a standard paradigm of GOFAI since the mid 50s at least.
The barebones algorithm:
search(State,Path,Path) :- is_final(State),!. % Done, bounce "Path" term
search(State,PathSoFar,PathOut) :-
generate_applicable_operators(State,Operators),
(is_empty(Operators) -> fail ; true),
select_operator(Operators,Op,PathSoFar),
apply_operator(State,Op,NextState), % depth-first / best first
search(NextState,[[NextState,Op]|PathSoFar],PathOut).
% Called like this, where Path will contain the reverse Path through
% State Space by which one may reach a final state:
search(InitialState,[[InitialState,nop]],Path).
First you need to represent a given state in this case the state of the board (at some time t).
We can either list the board positions and their content (w for white, b for black, e for empty token) or list the tokens and their positions. Let's list the board positions.
In Prolog, a term that can be easily pattern-matched is appropriate. The question already provides something: (w, w, w, e, b, b, b). This seems to be inspired by LISP and is not well adapted to Prolog. Let's use a list instead: [w, w, w, e, b, b, b]
The mapping of board positions to list positions shall be:
+---+---+
| 0 | 1 |
+---+---+---+
| 2 | 3 | 4 |
+---+---+---+
| 5 | 6 |
+---+---+
And we are done with setting up a state description!
Then you need to represent/define the operators (operations?) that can be applied to a state: they transform a valid state into another valid state.
An operator corresponds to "moving a token" and of course not all operators apply to a given state (you cannot move a token from field 1 if there is no token there; you cannot move a token to field 1 if there already is a token there).
So you want to write a predicate that links a board state to the operators applicable to that state: generate_applicable_operators/2
Then you need to select the operator that you want to apply. This can be done randomly, exhaustively, according to some heuristic (for example A*), but definitely needs to examine the path taken through the state space till now to avoid cycles: select_operator/3.
Then you apply the operator to generate the next state: apply_operator/3.
And finally recursively call search/3 to find the next move. This continues until the "final state", in this case [b, b, b, e, w, w, w] has been reached!
You can also use Iterative Deepening if you want to perform "breadth-first search" instead, but for that the algorithm structure must be modified.
And that's it.

Efficient way of generating graphs from source nodes

Let's say I have a graph G, and around each node I have a few source nodes xs. I have to create a new graph G' using xs=[[a, b, c], [d, e], [f]] nodes such that they won't conflict with grey donuts as shown in the figure below.
Expected output G' is [[a, d, f], [a, e, f], [b, e, f]]; all others are conflicting a gray donut.
I currently solved it by taking all permutation and combination of nodes xs. This works for smaller numbers of nodes, but as my number of nodes xs increases with bigger graph G, it soon becomes 100s of thousands of combination to try.
I am looking for an efficient algorithm which will help me speed things up and get me all the non-conflicting graphs with a minimum number of iterations.
You have a fairly obvious minimum set of edges for each stage of your path. They are both necessary and sufficient for your solution. For notational convenience, I'll label the original graph X--Y--Z. Your corresponding G' nodes are
X a b c
Y d f
Z f
You do this in two steps:
For each edge in G, you must test for validity each possible edge in G`. This consists of
X--Y [a, b, c] X [d, e]
a total of 6 edges; 3 qualify: set XY = [a--d, a--e, b--d]
Y--Z [d, e] X [f]
a total of 2 edges; 2 qualify: set YZ = [d--f, e--f]
Now, you need only generate all combinations of XY x YZ where the Y nodes match. If you sort the lists by the "inner" node, you can do this very quickly as
[a--d, b--d] x [d--f]
[a--e] x [e--f]
Most current languages have modules to perform combinations for you, so the code will be short enough.
Does that get you going?

How can I know if all nodes have been visited in a graph before reaching the intended node?

I have a knowledge base of this type:
connect(a, b).
connect(a, d).
connect(a, e).
connect(b, a).
connect(b, c).
...
My objective is, given an origin and a destiny, to go through all the existing nodes once, before reaching the final node.
So far this is what I have got:
path(O, D, L):-
path(O, D, [O], L).
path(D, D, _, [D]).
path(O, D, A, [O|T]):-
connect(O, I),
\+ member(I, A),
path(I, D, [I|A], T).
In order to deal with the double connections e.g. connect(a, b). connect(b, a). I use a list that saves every node I go through and before going into the recursion call I make sure that the node I am going to does not belong in that list.
Now I need to make sure that I go through all the existing nodes before reaching the final one. I have absolutely no idea how to even approach this. How can I ever be sure that I visited all the other nodes before reaching the last one?
You can test it with your own code (not using findall), by making a small change. Instead of throwing away the list of visited nodes, keep it. So, change path/4 to path/5 as follows:
path(D, D, V, V, [D]).
path(O, D, A, V, [O|T]):-
connect(O, I),
\+ member(I, A),
path(I, D, [I|A], V, T).
Now you can query path(a,c,[a], Visited, Path) and test if any connect node exists that is not a member of Visited.
You have defined a network as a list of edges. A quick-and-dirty way to collect all nodes would be, for example:
findall(X, ( connect(X, _) ; connect(_, X) ), Xs),
sort(Xs, Nodes)
This will first collect all "from"s and "to"s you have listed in your connect/2, then make a set out of it by sorting and removing duplicates.
At that point you can just compare this set to the path you found (after making a set out of it, too).
Obviously, it is important that your predicate fails there is no path that visits all nodes in the network defined by connect/2.

List all reachable nodes

I have a predicate that is bi-directional and tells, whether one node is connected to another.
E.g.
has(a, b).
has(b, c).
has(d, b).
Now I would like to list all nodes which can be reached (from a specific node) with a given number of steps.
connected_nodes(a, T, 2).
should therefore output
T = c
T = d
My current code looks like this:
connected_nodes(A, B, 0) :- write(A).
connected_nodes(A, B, N) :-
N > 0, M is N - 1,
has(A, X),
connected_nodes(X, B, M).
This works for T = c but not for T = d, as this is a bi-directional relation.
Am I thinking correctly in terms of recursion or how in which other way does this problem have to be solved?
Your connected predicate seems fine. It might have made more sense to make the base case rely on has, but it's up to you.
However, you say your has predicate is "bi-directional" but you haven't explicitly created a rule that indicates this.
The following code is a "bi-directional" version of your code:
has(a, b).
has(b, c).
has(d, b).
bi_has(X,Y) :- has(X,Y).
bi_has(X,Y) :- has(Y,X).
connected_nodes(A, B, 0) :- write(A).
connected_nodes(A, B, N) :-
N > 0, M is N - 1,
bi_has(A, X),
connected_nodes(X, B, M).
Note however that your query now returns a as a possible answer too. This makes since, because you never explicitly stated you don't want to return back to the same element after 2 steps.
If you don't want this behaviour, then you need to also keep a list of elements visited so far (i.e. an accumulator), and confirm that you're not revisiting elements.

Prolog confusion. Can someone explain how minimal works?

I understand the code up to minimal but after that there's too many variables and I keep losing track of what each one is doing. If someone could explain it or do it with renamed variables that would be an amazing help, as I think this code will probably come up on my Christmas exam and I want to be able to explain what's going on.
road(a, b, 1).
road(b, c, 1).
road(a, c, 13).
road(d, a, 1).
/*Getting from A to B through a list of places R in N kms*/
route(A,B,R,N) :- travel(A,B,[A],Q,N), reverse(Q,R).
/*Travelling from A to B through P a list of towns B|P of distance L*/
travel(A,B,P,[B|P],Dist) :- road(A,B,Dist).
/*Travelling from A to B through Visited, on your Route R with distance Distance*/
/*Find if there is a road from A to b and store the distance. Make sure C is not equal to B*/
travel(A,B,Visited,R,Distance) :-
road(A,C,Dist), C \== B,
/*Make sure C is not in Visited to avoid infinite loop,
use recursion to find the full route and distance */
\+member(C,Visited), travel(C,B,[C|Visited],R,Dist1), Distance is Dist + Dist1.
/*Find the shortest route from A to B*/
shortest(A,B,R,N) :-
setof([Route,Dist],route(A,B,Route,Dist),Set),
Set = [_|_], minimal(Set,[R,N]).
minimal([F|R],M) :- min(R,F,M).
/*The shortest path*/
min([],M,M).
min([[P,L]|R],[_,M],Min):- L < M, !, min(R,[P,L],Min).
min([_|R],M,Min) :- min(R,M,Min).
since setof gives a sorted list of solutions, it's sufficient to produce solutions of appropriate 'shape', placing first the value you want to minimize: try
shortest(A,B,R,N) :-
setof((Dist,Route), route(A,B,Route,Dist), [(N,R)|_]).

Resources