Prolog, "or" operator for rule statments - prolog

I am new to prolog and want to make a rule statement for whether 2 people are cousins.
This is my current code, I added "or" to where I need the or operator:
cousins(E, F) :- siblings(A, C) or siblings(A, D) or siblings(B, C) or siblings (B, D), parent(A, E), parent(B, E), parent(C, F), parent(D, F).
I need just one of the siblings() to pass, but all parent() must pass.

In Prolog, an "or" operator is ;. Or it can be achieved by having different clauses for the predicate.
Let's see what happens if your first alternative turns out to hold:
cousins( E, F):-
siblings(A, C),
parent( A, E),
parent( B, E),
parent( C, F),
parent( D, F).
Or, what happens if the 2nd holds?
cousins( E, F) :-
siblings(A, D),
parent( A, E),
parent( B, E),
parent( C, F),
parent( D, F).
Similar for 3rd and 4th:
cousins(E, F) :- siblings(B, C),
parent(A, E), parent(B, E), parent(C, F), parent(D, F).
cousins(E, F) :- siblings (B, D),
parent(A, E), parent(B, E), parent(C, F), parent(D, F).
Now you have your "or" condition expressed by the four clauses.
But you must have left many important details out. You probably wanted to have two pairs of parents, so you need to add the inequalities: parent(A, E), parent(B, E), A \= B etc. But then, the new 2nd clause is just a copy of the 1st, up to some variables renaming; same for the 3rd and 4th clauses. It'll suffice to leave just one of each pair.
But why would you need to know the both parents of a person? You don't, really. What does it matter, if it's a mother or a father? It doesn't. So, in the end, just one clause will be sufficient:
cousins( E, F):-
siblings(A, C),
parent (A, E),
parent( C, F).
You still have to check for some degenerate cases, so you won't ever end up proclaiming a person their own cousin.

Related

How can i calculate a non-weighted graph length for a path that is given

This is the code so far.
next_to(a, b).
next_to(a, c).
next_to(a, f).
next_to(b, c).
next_to(b, d).
next_to(b, e).
next_to(e, f).
next_to(g, h).
joint_with(X,Y):- next_to(X,Y) ;
next_to(Y,X).
show_path(Node, FinishNode, [Node,FinishNode]) :-
joint_with(Node, FinishNode).
show_path(Node, FinishNode, [Node | Restroute]) :-
joint_with(Node, ANode),
show_path(ANode, FinishNode, Restroute).
How can i change show_path to calculate the length aswell (Give explanation how it work's if possible thanks in advance)
According to Willem's advice, I constructed a solution for your problem which is the following:
next_to(a, b).
next_to(a, c).
next_to(a, f).
next_to(b, c).
next_to(b, d).
next_to(b, e).
next_to(e, f).
next_to(g, h).
joint_with(X, Y) :-
( next_to(X, Y)
; next_to(Y, X)
).
show_path(Node, FinishNode, [Node, FinishNode], _) :-
joint_with(Node, FinishNode).
show_path(Node, FinishNode, [Node|Restroute], Counter) :-
joint_with(Node, ANode),
show_path(ANode, FinishNode, Restroute, _),
length([Node|Restroute], Counter),
!.
But if backtracking doesn't finish Counter does not take its value.

Prolog Partial Matching

If there is a rule that cannot be satisfied with all parameters, is there a standard way to get a partial match with just some of the parameters?
For example, the following query can not find a solution:
?- query(A, B, C).
false.
But a solution can be found if we don't try to unify on C:
?- query_best_effort(A, B, C).
A = alfa,
B = bravo ;
I have the following code that implements this functionality. But is there a more Prolog-way to do this?
fact1(alfa).
fact2(bravo).
fact3(charlie).
rule1(A) :-
fact1(A).
rule2(B) :-
fact2(B).
rule3(C) :-
fact3(C),
C \== charlie.
query(A, B, C) :-
rule1(A),
rule2(B),
rule3(C).
query_best_effort(A, B, C) :-
query_chain3(A, B, C);
query_chain2(A, B);
query_chain1(A).
query_chain3(A, B, C) :-
query(A, B, C).
query_chain2(A, B) :-
\+query_chain3(A, B, _),
rule1(A),
rule2(B).
query_chain1(A) :-
\+query_chain2(A, _),
rule1(A).
First, a comment on programming style. When using disjunctions (;/2), always wrap them between parenthesis and avoid writing ; at the end of a line. In your case:
query_best_effort(A, B, C) :-
( query_chain3(A, B, C)
; query_chain2(A, B)
; query_chain1(A)
).
This recommended style contributes to code readability.
You can also avoid using negation (\+/1) by using instead the *->/2 soft-cut control construct implemented in several Prolog systems (a few systems, e.g. SICStus Prolog, implement it as an if/3 built-in predicate):
query_best_effort(A, B, C) :-
( query_chain3(A, B, C) *->
true
; query_chain2(A, B) *->
true
; query_chain1(A)
).
query_chain3(A, B, C) :-
query(A, B, C).
query_chain2(A, B) :-
rule1(A),
rule2(B).
query_chain1(A) :-
rule1(A).
The *->/2 control construct, unlike the standard ->/2 control construct, allows backtracking into the condition. When calling the query_best_effort/3 predicate, the query_chain2/2 predicate will only be called if there are no solutions for the query_chain3/3 goal and the query_chain1/1 predicate will only be called if there are no solutions for the query_chain3/3 and query_chain2/2 goals, which I assume was your intention with the use of disjunction and negation?
Sample call:
| ?- query_best_effort(A, B, C).
A = alfa
B = bravo
yes
Note, however, that *->/2 is, like negation, a non-logical control construct.

Finding a cycle in a simple Prolog graph

I am having trouble with this simple Prolog graph, i am trying to test for a cycle and have no idea why it isn't working. isPath seems to work, the problem is with cycle function which is supposed to check if there is a cycle on the given letter. Can anyone help?
path(a, b).
path(a, c).
path(a, f).
path(b, e).
path(c, d).
path(d, a).
path(d, h).
path(e, f).
path(e, g).
path(e, h).
path(f, g).
path(f, b).
path(h, g).
isPath(X, X) :-
path(X, Y).
isPath(X, Y) :-
path(X, Z),
isPath(Z, Y).
cycleIt(J) :-
isPath(J, K),
isPath(K, J).
You can use DCG !
How can you find cycles ? You need to find a node From, linked by an edge to another node Via, then from Via, you need to find a path, ending in From, and you must not have cycle during this search.
so :
cycle --> [X], {path(X, Y)},search(Y, X, []).
% the search is ended
search(From, To, _Visited)--> {path(From,To)}, [From,To].
% we try an another path using Via, which has not been already visited
search(From, To, Visited)--> {path(From,Via), \+member(Via, Visited)}, [From], search(Via, To, [Via|Visited]).
The result
?- phrase(cycle, A,[]).
A = [a, c, d, a] ;
A = [b, e, f, b] ;
A = [c, d, a, c] ;
A = [d, a, c, d] ;
A = [e, f, b, e] ;
A = [f, b, e, f] ;
false.

testing in the console

The consult ?- go(c, g). returns false, but states true for ?- go(a, d).. I do not actually understand it, as I have added the proper rules, and for most of them it works.
Here are the statements I'm using:
door(a, b).
door(b, c).
door(c, d).
door(b, e).
door(e, f).
door(e, g).
go(FromRoom, ToRoom):-
door(FromRoom,ToRoom).
go(FromRoom, ToRoom):-
door(ToRoom, FromRoom).
go(FromRoom, ToRoom) :-
door(FromRoom, NextRoom),
go(NextRoom, ToRoom), !.
go(FromRoom, ToRoom):-
door(ToRoom,NextRoom),
go(NextRoom, FromRoom), !.
You need to add accumulator to your predicate to avoid got stuck in inf loop.
door(a, b).
door(b, c).
door(c, d).
door(b, e).
door(e, f).
door(e, g).
go(From, To, T) :-
T=[From|T1],
go(From, To, [To], T1).
go(From, To,T, T) :-
door(From, To),!.
go(From,To,T,T) :-
door(To,From),!.
go(From, To, Acc,T) :-
door(X, Do),!,
\+ member(X, Acc),
go(From, X, [X|Acc],T).
go(From,To,Acc,T) :-
door(X,Z),!,
\+member(Z,Acc),
go(X,To,[X|Acc],T).
You fourth rule should read
go(FromRoom, ToRoom):-
door(ToRoom,NextRoom),
go(FromRoom,NextRoom),!.
because you already swapped the search order in calling door/2, but this leads to looping, as rightly remarked by #whd. Here a version that 'returns' the path
go(Room, Room, Path, Path).
go(FromRoom, ToRoom, SoFar, Path) :-
( door(FromRoom, NextRoom) ; door(NextRoom, FromRoom) ),
\+ member(NextRoom, SoFar),
go(NextRoom, ToRoom, [NextRoom|SoFar], Path).
test:
?- go(c,g,[],P).
P = [g, e, b, c, d] ;
P = [g, e, b] ;
false.
Due to Prolog search order, it 'takes a tour' in d before going back. It's easy to avoid acting on the SoFar parameter at top level call...

setof in prolog

what is the source code of setof in prolog?
?- listing(setof).
:- meta_predicate setof(?,0,-).
setof(A, B, F) :-
free_variable_set(A, B, D, C),
( C==v
-> findall(A, D, E),
E\==[],
sort(E, F)
; findall(C-A, D, E),
( ground(E)
-> sort(E, G),
pick(G, C, F)
; bind_bagof_keys(E, _),
sort(E, G),
pick(G, C, H),
sort(H, F)
)
).
true.
In case you are looking for the Sicstus built-in predicate implementation, it can be found here: http://www.sics.se/sicstus/docs/4.2.1/html/sicstus/mpg_002dref_002dsetof.html as:
setof(+Template, +Generator, -Set)
Unlike findall/3 and bagof/3, setof does not return duplicates and does give sorted order.
I.

Resources