Grounding in Prolog given a predicate and a list - prolog

Given a predicate and a list I want a list of all the possible ways of grounding. For example:
gounding(predicate(X), [a,b,c], Grounded).
Should return
[predicate(a), predicate(b), predicate(c)]
And I would also like it to work with more than one variable, for example:
grounding(predicate(X,Y), [a,b,c], Grounded).
Grounded = [predicate(a,a), predicate(a,b), predicate(a,c), predicate(b,a), predicate(b,b), predicate(b,c), predicate(c,a), predicate(c,b), predicate(c,c)]
The problem is given by the fact that the predicate is not always the same, so it needs to be passed as a variable. Like:
grounding(Predicate, Arity, [a,b,c], Grounded).
Is there something that already does this or should it be done manually?
I tried using atom_concat with the name of the predicate, the brackets and the elements of the list, but it returns the list with quotes like:
['predicate(a)', 'predicate(b)', 'predicate(c)']

Let's start with a simpler problem: Given a list of variables and a list of ground values, assign those ground values to the variables. For example:
?- variables_values([X], [a, b, c]).
X = a ;
X = b ;
X = c.
This can be implemented like this:
variables_values([], _Values).
variables_values([Variable | Variables], Values) :-
member(Variable, Values),
variables_values(Variables, Values).
A bigger example:
?- variables_values([X, Y], [a, b, c]).
X = Y, Y = a ;
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = a ;
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = a ;
X = c,
Y = b ;
X = Y, Y = c.
The term_variables/2 predicate gives you a list of all the variables in a term. You can combine this with the above predicate:
?- Pattern = predicate(X, Y), term_variables(Pattern, Variables), variables_values(Variables, [a, b, c]).
Pattern = predicate(a, a),
X = Y, Y = a,
Variables = [a, a] ;
Pattern = predicate(a, b),
X = a,
Y = b,
Variables = [a, b] ;
Pattern = predicate(a, c),
X = a,
Y = c,
Variables = [a, c] ;
Pattern = predicate(b, a),
X = b,
Y = a,
Variables = [b, a] . % etc.
Note that instantiating the variables in the list also instantiates them in the pattern -- the variables are shared.
Given this, the last piece of the puzzle is a predicate that computes a list of instantiations of a pattern, given some predicate that instantiates variables. findall/3 is the right tool for this job:
pattern_values_grounded(Pattern, Values, Grounded) :-
term_variables(Pattern, Variables),
findall(Pattern, variables_values(Variables, Values), Grounded).
This does what you seem to want:
?- pattern_values_grounded(predicate(X), [a, b, c], Grounded).
Grounded = [predicate(a), predicate(b), predicate(c)].
?- pattern_values_grounded(predicate(X, Y), [a, b, c], Grounded).
Grounded = [predicate(a, a), predicate(a, b), predicate(a, c), predicate(b, a), predicate(b, b), predicate(b, c), predicate(c, a), predicate(c, b), predicate(..., ...)].

Related

Incorrect output when trying to query in a depth first search implementation for prolog

I just can't seem to get the correct output - I am supposed to get -
?- dfs([a], X).
X = [a, f, i] ;
false.
But I get -
?- dfs([a], X).
X = [a|f] ;
% Representation of a tree
% choose initial state a
arc(a, b).
arc(a, f).
arc(b, c).
arc(b, d).
arc(b, e).
arc(f, g).
arc(f, i).
arc(i, j).
arc(i, k).
% the goal
goal(i).
dfs([Node|_], [Node|X]) :-
goal(X).
dfs([Node|_], [Node|X]) :-
expands([Node|_], NewNode),
append([Node|_], NewNode, appendedN),
dfs(appendedN, X).
% expands(+Path, ?NewNode).
% -- Path: is a list of nodes of the form Path=[Node|Nodes], where
% Node is the node we want to expand and Nodes is a list
% of remaining nodes already expanded and containing the root.
% -- NewNode: is a constant representing the node we want to go to,
% as there is an link to it from where we are currently.
%
expands([Node|_], NewNode):-
arc(Node, NewNode).
Your program matches the first clause, dfs([Node|_], [Node|X]), and nothing else, producing X = [a|i] .
Here's a working version.
% Representation of a tree
% choose initial state a
arc(a, b).
arc(a, f).
arc(b, c).
arc(b, d).
arc(b, e).
arc(f, g).
arc(f, i).
arc(i, j).
arc(i, k).
% the goal
goal(i).
% You can expand a starting symbol S to a list L if G is your goal, S expands
% to G in list L1, and you append the two lists.
dfs([S], L) :-
goal(G),
expands(S, G, L1),
append([S], L1, L).
% X expands to Y in list [Y] if there's a direct arc from X to Y (base case).
expands(X, Y, [Y]) :-
arc(X, Y).
% X expands to Z in list [Y|L] if there's a direct arc from X to Y and Y
% expands to Z in list L (recursive case).
expands(X, Z, [Y|L]) :-
arc(X, Y),
expands(Y, Z, L).
In this version, expands() produces all of the lists that start with a:
?- expands(a, X, L).
X = b,
L = [b] ;
X = f,
L = [f] ;
X = c,
L = [b, c] ;
X = d,
L = [b, d] ;
X = e,
L = [b, e] ;
X = g,
L = [f, g] ;
X = i,
L = [f, i] ;
X = j,
L = [f, i, j] ;
X = k,
L = [f, i, k] ;
false.
Then dfs() confirms that the goal i has been reached and adds the start symbol a to the head of the list:
?- dfs([a], X).
X = [a, f, i] ;
false.

define a predicate solution/3 which is true when its three arguments, all lists, has the third list containing all elements of the first two arguments

solution([ ], List, List).
solution([Head|Tail], List,[Head|Result]):-
solution(Tail, List,Result).
expected output
| ?- Solution(X,Y,[a,b,c]).
X = [a,b,c]
Y = [] ? ;
X = [a,b]
Y = [c] ? ;
X = [a,c]
Y = [b] ? ;
X = [a]
Y = [b,c] ? ;
X = [b,c]
Y = [a] ? ;
X = [b]
Y = [a,c] ? ;
X = [c]
Y = [a,b] ? ;
X = []
Y = [a,b,c] ? ;
actual output
X = []
Y = [a,b,c] ? ;
X = [a]
Y = [b,c] ? ;
X = [a,b]
Y = [c] ? ;
X = [a,b,c]
Y = [] ? ;
It is not going through all the possible solutions that can be made from the predicate defined. i am expecting the output to be as shown above containing all the solutions of combining 2 lists together
Any help?
Your predicate is missing some clauses. The first clause says that if the first list is exhausted, then the result is the second list.
The second clause specifies that if the first list is not exhausted, we simply take the first element of that list as a result. This thus means that you basically implemented an append/3 predicate [swi-doc].
Based on your sample output, there is however a decision whether to take from the first list, or the second list. We thus should implement a clause like:
solution([H1|T1], L2, [H1|R]) :-
solution(T1, L2, R).
solution(L1, [H1|T2], [H1|R]) :-
solution(L1, T2, R).
If both lists are exhausted, we can return an empty list, so we can define a base-clause like:
solution([], [], []).
and thus obtain as full solution:
solution([], [], []).
solution([H1|T1], L2, [H1|R]) :-
solution(T1, L2, R).
solution(L1, [H1|T2], [H1|R]) :-
solution(L1, T2, R).
This then gives us:
?- solution(X,Y,[a,b,c]).
X = [a, b, c],
Y = [] ;
X = [a, b],
Y = [c] ;
X = [a, c],
Y = [b] ;
X = [a],
Y = [b, c] ;
X = [b, c],
Y = [a] ;
X = [b],
Y = [a, c] ;
X = [c],
Y = [a, b] ;
X = [],
Y = [a, b, c].

Prolog: eliminate repetitions in query

I've been trying to write a simple code, that would behave in this manner:
| ?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? ;
X = [a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
And
| ?- hasCoppiesOf([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = ...
This desire resulted in next piece of code:
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B).
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
And it gives me what I want on the second query, however, the first results in:
?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
It seems to be working fine, but that repetition of the same answers bothers me. It's, probably, a simple mistake, but is there a way to make the output prettier?
And honestly, that a mystery, why Prolog treats two identical arrays as different answers.
Or maybe it's just something wrong with my system?
Edit:
The gentle guidance of the person in the comments helped me to solve this issue. However, if this question will be reading the person who wants to solve exactly the same problem - code not really working well, my apologies.
I think you just made your predicate more complex than it needs to be, probably just overthinking it. A given solution may succeed in multiple paths through the logic.
You can do this without append/3 by aligning the front end of the lists and keep the original list to "reset" on repeats:
% Empty list base cases
dups_list([], []).
dups_list([_|_], []).
% Main predicate, calling aux predicate
dups_list(L, Ls) :-
dups_list(L, L, Ls).
% Recursive auxiliary predicate
dups_list([], [_|_], []).
dups_list([], [X|Xs], [X|Ls]) :-
dups_list(Xs, [X|Xs], Ls).
dups_list([X|Xs], L, [X|Ls]) :-
dups_list(Xs, L, Ls).
Here are some results:
| ?- dups_list(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? a
X = [a,b,a,b]
X = [a,b,a,b,a,b,a,b]
no
| ?- dups_list([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ?
...
| ?- dups_list(A, B).
A = []
B = [] ? ;
A = [_|_]
B = [] ? ;
A = [C]
B = [C] ? ;
A = [C]
B = [C,C] ? ;
A = [C,D]
B = [C,D] ? ;
A = [C]
B = [C,C,C] ? ;
A = [C,D,E]
B = [C,D,E] ? ;
...
There may be a way to simplify the solution just a bit more, but I haven't played with it enough to determine if that's the case.
I think this is what you're trying for...
coppies(Z,Z,[]).
coppies(X,Z,[Y|Ys]):- \+member(Y,Z),coppies(X,[Y|Z],Ys).
coppies(X,Z,[Y|Ys]):- member(Y,Z),coppies(X,Z,Ys).
copies(M,[Y|Ys]):-coppies(M,[],[Y|Ys]).
Input:
copies(X,[1,2,1,2,1,2]).
Output:
X = [2, 1].
BTW I've used some different names instead..
Okay, I got your problem, you want to eliminate the repetitions.
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!. %Change here, place a cut after the termination.
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
This is the change that you need to make.
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!.
A Cut '!' terminates the unwanted backtracking and thereby repetitions.

How to check if list 2 contains all of list 1s elements?

I'm quite new to Prolog. I got stuck with this problem:
If I have two lists, how do I check if list 1 contains all of the elements of the second list, but they don't have to be equal. So list 2 might contain more elements.
I know I can use member/2 to check if a certain element is in a list. But I don't know how to not include these members of both lists after I checked them. So for example:
If I have list A = [a,b,c,a] and list B = [a,b,c,d,e] and I start by checking if the first 'a' from list A is in list B. Obviously this returns a True, but if I check the last 'a' from list A, I should get a False returned, since list A has 2 'a's and B only 1, instead I get True returned. I really have no clue on how to fix this problem.
I would really appreciate if someone could help me :)
Thanks!
Edit: Explained my question a bit more
select/3 does exactly what we want:
is_sublist([], []).
is_sublist([], [_|_]).
is_sublist([H|T], L) :-
once(select(H, L, L2)),
is_sublist(T, L2).
We wrap it in once/1 to avoid redundant successes in cases where an element appears multiple times.
Note: you can remove once/1 to get more working behaviors:
?- is_sublist(Z,[a,b,c]). % Without once
Z = [] ;
Z = [a] ;
Z = [a, b] ;
Z = [a, b, c] ;
Z = [a, c] ;
Z = [a, c, b] ;
Z = [b] ;
Z = [b, a] ;
Z = [b, a, c] ;
Z = [b, c] ;
Z = [b, c, a] ;
Z = [c] ;
Z = [c, a] ;
Z = [c, a, b] ;
Z = [c, b] ;
Z = [c, b, a] ;
false.
This will not enumerate all possible answers in the opposite direction, so not everything is perfect:
?- is_sublist([a,b],Z). % Without once
Z = [a, b] ;
Z = [a, b, _886|_888] ;
Z = [a, _880, b|_888] ;
Z = [a, _880, _892, b|_900] ;
Z = [a, _880, _892, _904, b|_912]
…

Learning prolog, some list functions

I am working on an assignment that deals with lists in prolog. The basic idea is that given a list, prolog should be able to determine if a value is repeated at all, repeated only once, or repeated only twice, etc. I thought the simplest solution would be to count the number of times a value occurs and then use that count to determine how many times it is repeated.
list_count([],X,0).
list_count([X|T],X,Y) :- list_count(T,X,Z), Y is 1 + Z.
list_count([X1|T],X,Z) :- X1 \= X, list_count(T,X,Z).
repeated_in(+E,+List) :- list_count(List,E,Num), Num >= 2.
No matter what I do though my first predicate always fails. Help?
list_count/3 does work. I think the only issue is the improper usage of prefix '+': try
% repeated_in(+E,+List)
repeated_in(E,List):- list_count(List,E,Num), Num >= 2.
note: prefixing arguments is used for documentation purpose, as a recap about mode usage
Here a logically pure implementation, based on
if_/3 and (=)/3 by #false.
atLeastOnceMember_of(E,[X|Xs]) :-
if_(E = X, true, atLeastOnceMember_of(E,Xs)).
atLeastTwiceMember_of(E,[X|Xs]) :-
if_(E = X, atLeastOnceMember_of(E,Xs), atLeastTwiceMember_of(E,Xs)).
First, let's look at the queries you suggested in your question:
?- atLeastTwiceMember_of(a,[a,b,a,b,a,c]).
true. % succeeds deterministically
?- atLeastTwiceMember_of(b,[a,b,a,b,a,c]).
true. % succeeds deterministically
?- atLeastTwiceMember_of(c,[a,b,a,b,a,c]).
false.
?- atLeastTwiceMember_of(x,[a,b,a,b,a,c]).
false.
The code is monotone, so we get logically sound answers for more general uses, too!
?- atLeastTwiceMember_of(X,[a,b,a,b,a,c]).
X = a ;
X = b ;
false.
At last, let us consider a generalization of above query:
?- atLeastTwiceMember_of(X,[A,B,C,D,E,F]).
X = A, A = B ;
X = A, A = C, dif(C,B) ;
X = A, A = D, dif(D,C), dif(D,B) ;
X = A, A = E, dif(E,D), dif(E,C), dif(E,B) ;
X = A, A = F, dif(F,E), dif(F,D), dif(F,C), dif(F,B) ;
X = B, B = C, dif(C,A) ;
X = B, B = D, dif(D,C), dif(D,A) ;
X = B, B = E, dif(E,D), dif(E,C), dif(E,A) ;
X = B, B = F, dif(F,E), dif(F,D), dif(F,C), dif(F,A) ;
X = C, C = D, dif(D,B), dif(D,A) ;
X = C, C = E, dif(E,D), dif(E,B), dif(E,A) ;
X = C, C = F, dif(F,E), dif(F,D), dif(F,B), dif(F,A) ;
X = D, D = E, dif(E,C), dif(E,B), dif(E,A) ;
X = D, D = F, dif(F,E), dif(F,C), dif(F,B), dif(F,A) ;
X = E, E = F, dif(F,D), dif(F,C), dif(F,B), dif(F,A) ;
false.

Resources