Prolog - Connectivity Graph Beginner - prolog

I am a beginner in Prolog and I have a task to do.
I need to check if the graph is connected.
For now I have that...
graph(
[arc(a,b)],
[arc(a,f)],
[arc(b,c)],
[arc(c,d)],
[arc(c,e)],
[arc(e,d)],
[arc(f,c)],
[arc(f,e)],
[arc(f,g)],
[arc(g,c)],
[arc(c,a)]).
edge(X,Y):-arc(X,Y);arc(Y,X).
path(X,Y):-edge(X,Y).
path(X,Y):-edge(X,Z),path(Z,Y).
triangle(X,Y,Z):-arc(X,Y),arc(Y,Z),arc(Z,X).
cycle(X):-arc(X,Y),path(Y,X).
connectivity([]):-forall(member(edge(X,Y)),path(X,Y)).
Check:
connectivity(graph).
upper I have arc(x,y) and I need check if every pair is connected.
Could u help me ?

Since you changed the question after I was almost done I will post what would solve the question before the change and you can figure out how to change it to meet your update.
arc(a,b).
arc(a,f).
arc(b,c).
arc(c,d).
arc(c,e).
arc(e,d).
arc(f,c).
arc(f,e).
arc(f,g).
arc(g,c).
arc(c,a).
edge(X,Y) :-
arc(X,Y), !.
edge(X,Y) :-
arc(Y,X).
path_prime(Visited,X,Y) :-
\+ member(X,Visited),
edge(X,Y), !.
path_prime(Visited,X,Y) :-
\+ member(X,Visited),
edge(X,Z),
path_prime([X|Visited],Z,Y).
path(X,X) :-
ground(X), !.
path(X,Y) :-
path_prime([],X,Y).
nodes(Nodes) :-
setof(A,B^arc(A,B),Starts),
setof(B,A^arc(A,B),Ends),
union(Starts,Ends,Nodes).
connected(X,Y) :-
nodes(Nodes),
member(X,Nodes),
member(Y,Nodes),
path(X,Y).
The first thing that has to be done is to get a list of the unique nodes which will be a set.
This can be done using
nodes(Nodes) :-
setof(A,B^arc(A,B),Starts),
setof(B,A^arc(A,B),Ends),
union(Starts,Ends,Nodes).
Notice that both the start and the end node of an arc are done separately. In particular notice that the node d is only in the destination of an arc.
Since you included edge(X,Y):-arc(X,Y);arc(Y,X). in your question, this indicated that the arcs should not be directional and so it is possible to get cycles. To avoid the cycles the list of visited nodes is added to the argument list and checked before proceeding.
As no test cases or examples of a correct solution were given, some times a node connected to itself is valid and so the clause
path(X,X) :-
ground(X), !.
was added.
This is by no means an optimal or best way to do this, just to give you something that works.
Partial run
?- connected(X,Y).
X = Y, Y = a ;
X = a,
Y = b ;
X = a,
Y = c ;
X = a,
Y = d ;
X = a,
Y = e ;
X = a,
Y = f ;
X = a,
Y = g ;
X = b,
Y = a ;
X = Y, Y = b ;
X = b,
Y = c ;
...
As I often comment, you should do problems with pen an paper first before writing code. If you don't know exactly what the code will be before you start typing the first line of code then why are you typing in code?
Questions from comments:
And setof ,union ,whats mean? Im rly beigneer and I don't understand that language and predicates.
setof/3 collects all of the values from arc/2. Since only one of the two values is needed, ^ tells setup/3 not to bind the variable in the Goal, or in beginner terms to just ignore the values from the variable.
union/3 just combines the to sets into one set; remember that a set will only have unique values.

Related

how exactly an atom/1 predicate works in prolog?

I have been trying to solve a pathfinding problem in Prolog.where the predicates are
edge(a,b).
edge(a,c).
edge(b,d).
edge(c,d).
edge(d,e).
edge(d,f).
edge(f,g).
the rules is
edge(X,Y) :- edge(X,Z), edge(Z,Y).
then when I compiled and run the query
| ?- edge(a,X).
it is showing
Fatal Error: local stack overflow (size: 8192 Kb, environment variable used: LOCALSZ)
then I searched for the solution and found that including atom(x).,atom(y). in our rule can solve the stack overflow problem . i.e the new rule is
edge(X,Y) :- atom(X), atom(Y), edge(X,,Z), edge(Z,Y). and yes it did solved the stack overflow problem .but,I would like to know how exactly this (atom/1)
predicate is solving my problem here?and what does it do to our variables X,Y to solve the StackOverflow problem?
I am a newbie to Prolog any help would be appreciated
thank you. :)
First on naming, the edge/2 name doesn't describe your predicate very well. You probably really want path/2 which consists of one or more edges.
Does atom/1 really solve your problem? In other words, does edge(X, Y) really now provide all of the correct solutions to a query? All that atom/1 does is ensure that its argument is an atom, so it cannot be an unbound variable. So edge(X, Y) does not provide all of the correct solutions. It only yields those solutions that you have direct facts for, since the predicate edge(X, Y) as currently defined always fails with either X or Y unbound.
| ?- edge(a, Y).
Y = b ? ;
Y = c ? ;
no
Where is the solution Y = d for example? edge(X, Y) is only picking up the solutions that are given in your edge/2 facts, but no solutions that include multiple connected edges.
Your original problem is due to infinite recursion, which is a result of edge/2 calling itself unnecessarily. Naming can actually be important here since it makes the logic more precise and correct. We can say that edge(X, Y) means that X and Y form an edge (X and Y are directly connected). We can say that path(X, Y) means there's a path from X to Y via one or more edges. In other words, a path from x to y can either be an edge from x to y, or it can be an edge from x to z and a path from z to y.
path(X, Y) :- edge(X, Y).
path(X, Y) :- edge(X, Z), path(Z, Y).
Now we get:
| ?- path(a, X).
X = b ? a
X = c
X = d
X = e
X = f
X = g
X = d
X = e
X = f
X = g
(1 ms) no
| ?-
There are duplicates since there may be multiple ways of getting from a to e for example. If you included an argument that showed the traversed path, this would become evident.
This solution isn't the end of the story, however. Your current facts are such that there are no "circuitous" paths (paths that eventually revisit the same node if followed). To handle that, you need a predicate argument to keep track of what nodes/edges you've traversed already and avoid traversing them again.

Prolog - simplify derivative

so I just got started with Prolog this semester, and got the homework to implement a pretty basic d(function, variable, derivative) which I did like this:
d(X,X,1) :- !.
d(C,X,0) :- atomic(C). %, (C \= X).
d(X**E,X,E*X**(E-1)).
d(U+V,X,A+B) :- d(U,X,A), d(V,X,B).
d(U-V,X,A-B) :- d(U,X,A), d(V,X,B).
d(U*V,X,DU*V+U*DV) :- d(U,X,DU), d(V,X,DV).
d(U/V,X,(DU*V-U*DV)/(V*V)) :- d(U,X,DU), d(V,X,DV).
I know this is not complete, but it covers all the tasks required in the exercise.
However,
?- d((x*x+2*x+3)/(3*x),x,R).
leads to
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)).
which doesn't look pretty at all. is/2 unfortunately doesn't like my x as it is not a number...
Is there a simple solution to achieve a cleaner result?
I would rather see this as two separate problems:
First, get derivation right (you're probably getting close, depending on your concrete requirements).
Then, work on simplifying expressions on an algebraic level. Exploit algebraic identities, see if applying the laws of commutativity / associativity / distributivity on some subexpressions enable their rewriting into something equivalent (but simpler / more compact).
As a starting point, you may want to look at the somewhat related question "Replacing parts of expression in prolog".
Here's a simplistic sketch how you could do the simplification—using iwhen/2 to safeguard against insufficient instantiation:
expr_simplified(A, B) :-
iwhen(ground(A), xpr_simplr(A,B)).
xpr_simplr(A, B) :-
( atomic(A)
-> A = B
; ( A = X+0 ; A = 0+X ; A = 1*X ; A = X*1 )
-> xpr_simplr(X, B)
; ( A = 0*_ ; A = _*0 )
-> B = 0
; A = X+X
-> B = X*2
; A = X*X
-> B = X**2
; A = X**1
-> B = X
; A =.. [F|Xs0], % defaulty catch-all
maplist(xpr_simplr, Xs0, Xs),
B =.. [F|Xs]
).
Let's see what it does with the expression you gave. We apply expr_simplified/2 until we reach a fixed point:
?- A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)),
expr_simplified(A,B),
expr_simplified(B,C),
expr_simplified(C,D).
A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)),
B = ((x+x+(0+2))*(3*x)-(x**2+2*x+3)*(0+3))/(3*x)**2,
C = ((x*2+2)*(3*x)-(x**2+2*x+3)*3)/(3*x)**2,
D = C. % fixed point reached
As imperfect as the simplifier is, the expression got a lot more readable.
a possibility to get a number is to replace each instance of variable x with a value, visiting the derived tree. You should do writing a clause to match each binary operator, or use a generic visit, like
set_vars(E, Vs, Ev) :-
E =.. [F,L,R],
set_vars(L, Vs, Lv),
set_vars(R, Vs, Rv),
Ev =.. [F,Lv,Rv].
set_vars(V, Vs, N) :- memberchk(V=N, Vs).
set_vars(V, _, V).
that yields
?- d((x*x+2*x+3)/(3*x),x,R), set_vars(R,[x=5],E), T is E.
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)),
E = ((1*5+5*1+ (0*5+2*1)+0)* (3*5)- (5*5+2*5+3)* (0*5+3*1))/ (3*5* (3*5)),
T = 0.29333333333333333
but, there is a bug in your first clause, that once corrected, will allow to evaluate directly the derived expression:
d(X,V,1) :- X == V, !.
...
now, we can throw away the utility set_vars/3, so
?- d((T*T+2*T+3)/(3*T),T,R), T=8, V is R.
T = 8,
R = ((1*8+8*1+ (0*8+2*1)+0)* (3*8)- (8*8+2*8+3)* (0*8+3*1))/ (3*8* (3*8)),
V = 0.3177083333333333.

Checking a combination (of a list) while creating it in Prolog

In our homework we are given a number of people and who knows who in the form of a database,
like this:
person(person1).
person(person2).
person(person3).
person(person4).
person(person5).
knows(person1,person2).
knows(person1,person3).
knows(person2,person4).
knows(person3,person5).
The database can contain any number of people with any set of connections.
We have a predicate (findall) that generate a list of the people one person (X) knows:
i.e.
findall(Y, knows(Y, person1);knows(person1, Y), AllPeople).
Y = [person2, person3] .
Then have a predicate that generate a combination of these people.
comb2(_,[]).
comb2([X|T],[X|Comb]):-comb2(T,Comb).
comb2([_|T],[X|Comb]):-comb2(T,[X|Comb]).
Disclaimer: we got this code snippet from:
http://ktiml.mff.cuni.cz/~bartak/prolog/combinatorics.html
i.e.
comb2([person2, person3], X).
X = [] ;
X = [person2] ;
X = [person2, person3] ;
X = [person3] ;
false.
The problem is that our code does a check on every combination (to see that no one in the group know anyone else in the group), and some of the test-cases have people with up to 30 friends (meaning astronomical amounts of combinations).
What we need is some way to test if anyone in the combination we are building know anyone else in the combination, while we are building it.
If I've correctly understood what you meant, an answer is to use findall/3 again with AllPeople to do just that.
% Assume that your code is here..
knows(person2,person3).
knows(person3,person2).
group(G) :-
G = [_,_|_],
forall(
( member(A, G)
, member(B, G)
, A \== B), knows(A, B)).
Corresponding query is:
?- One = person1,
findall(E
, knows(E, One)
; knows(One, E), AllPeople),
findall(G, (comb2(AllPeople, G), group(G)), Groups).
// ==> Groups = [[person2,person3]]

Prolog Set List's Head

append([],U,U).
append([X|U1],U2,[W|U3]) :- **W = X** , append(U1,[X|U2],[I|Quyruk]) ,
**W = I**, U3 = Quyruk .
This code appends first two lists when I delete "W is X".
This code has unnecessary variables like "W is X" but they are about my question.
When I set any value to "W" between ":-" and ",append..." like "W is X" or "W = 3" or "W = 6" -- returns false.
Why can't I set any value to the W at that position in code but I CAN set "W = I" at the end of the code?
The query is append([1,2],[3],U). I want to get [2,1,3] at this code
at append([1,2,3],[4,5,6],U). I want to get [3,2,1,4,5,6].
append([1],[2,3],U). returns [1,2,3] , when I take the length of first list "1" (when first list only has one element) the code is perfect ; but when I take the length of first list >1 (when first list has more than one element) the code returns false.
In prolog, you can't assign variables, and then reassign them. Variables are unified and instantiated. Once instantiated, they cannot be re-instantiated inside of a clause. So if you have this inside of a clause:
W = X,
...
W = I,
Then first W is unified with X (=/2 is the unification operator). That means they either both now have the same value instantiated (if at least one was instantiated before), or their values will be forced to be identical instantiation later in the clause. When W = I is encountered later, then I must be unifiable with W or the clause will fail. If I has a specific value instantiated that is different from the instantiation of W (and, therefore, X), the clause will necessarily fail.
Let's see it happen (note I changed the name to my_append since Prolog rejects redefining the built-in predicate, append):
my_append([],U,U).
my_append([X|U1], U2, [W|U3]) :-
W = X,
my_append(U1, [X|U2], [I|Quyruk]),
write('I = '), write(I), write('; W = '), write(W), nl,
W = I,
U3 = Quyruk.
If we run:
?- my_append([1], [1,2], L).
I = 1; W = 1
L = [1,2,3]
yes
Life is good. Now let's try:
| ?- my_append([1,2], [3,4], L).
I = 2; W = 2 % This will be OK
I = 2; W = 1 % Uh oh... trouble
no
Prolog cannot unify 1 and 2, as I described above. They are two different values. So the predicate fails due to the W = I statement.
The solution is a little simpler than what you're attempting (although you are very close):
% Append empty to list gives the same list
my_append([], U, U).
% Append of [X|U1] and U2 is just append U1 and [X|U2]
% Or, thought of another way, you are moving elements of the first list
% over to the head of the second one at a time
my_append([X|U1], U2, U3) :-
my_append(U1, [X|U2], U3).
| ?- my_append([1,2,3],[4,5,6],L).
L = [3,2,1,4,5,6]
yes
The essence of this was in your code. Those other variables were just getting in the way (as C.B. pointed out). :)
The is operator is specifically used to compare or unify integers. W = I Is attempting to unify W with I (regardless of type). When you Unify W with X (assuming X is an integer), you have already unified W, and if X\=I (doesn't unify) you will return false.
In your example, W unifies with 1, but then you try to unify it with 2.
You have a lot of unnecessary variables, here is a very simple implementation of append:
append([],XS,XS).
append([X|XS],YS,[X|ZS]):- append(XS,YS,ZS).
To understand whats going wrong with your code, lets walk through it
append([],U,U).
append([X|U1],U2,[W|U3]) :- W is X , append(U1,[X|U2],[I|Quyruk]) , W = I, U3 = Quyruk .
?-append([1,2,3],[4,5,6],U).
I will use X1,X2,... to differentiate between different bindings.
In the first call, X unifies with 1, U1 unifies with [2,3] and U2 unifies with [4,5,6]. W and U3 are not yet bound before going into the horn clause.
W is X unifies W with 1.
append(U1,[X|U2],[I|Quyruk]) is calling append([2,3],[1,4,5,6],[I|Quyruk]). Already you should see that your recursion isn't working correctly.

prolog function returning memory locations instead of values

just started programming with prolog and I'm having a few issues. The function I have is supposed to take a value X and copy it N number of times into M. My function returns a list of N number of memory locations. Here's the code, any ideas?
duple(N,_,M):- length(M,Q), N is Q.
duple(N,X,M):- append(X,M,Q), duple(N,X,Q).
Those are not memory adresses. Those are free variables. What you see is their internal names in your prolog system of choice. Then, as #chac pointed out (+1 btw), the third clause is not really making sense! Maybe you can try to tell us what you meant so that we can bring light about how to do it correctly.
I'm going to give you two implementations of your predicate to try to show you correct Prolog syntax:
duple1(N, X, L) :-
length(L, N),
maplist(=(X), L).
Here, in your duple1/3 predicate, we tell prolog that the length of the resulting list L is N, and then we tell it that each element of L should be unified with X for the predicate to hold.
Another to do that would be to build the resulting list "manually" through recursion:
duple2(0, _X, []).
duple2(N, X, [X|L]) :-
N > 0,
NewN is N - 1,
duple1(NewN, X, L).
Though, note that because we use >/2, is and -/2, ie arithmetic, we prevent prolog from using this predicate in several ways, such as:
?- duple1(X, Y, [xyz, xyz]).
X = 2,
Y = xyz.
This worked before, in our first predicate!
Hope this was of some help.
I suppose you call your predicate, for instance, in this way:
?- duple(3,xyz,L).
and you get
L = [_G289, _G292, _G295] ;
ERROR: Out of global stack
If you try
?- length(X,Y).
X = [],
Y = 0 ;
X = [_G299],
Y = 1 ;
X = [_G299, _G302],
Y = 2 ;
X = [_G299, _G302, _G305],
Y = 3 ;
X = [_G299, _G302, _G305, _G308],
Y = 4 .
...
you can see what's happening:
your query will match the specified *M*, displaying a list of M uninstantiated variables (memory locations), then continue backtracking and generating evee longer lists 'til there is stack space. Your second rule will never fire (and I don't really understand its purpose).
A generator is easier to write in this way:
duple(N,X,M) :- findall(X,between(1,N,_),M).
test:
?- duple(3,xyz,L).
L = [xyz, xyz, xyz].

Resources