prolog: subsets of length k - prolog

in class we went over the subset_of/2 predicate that my teacher gave as follows:
subset_of([],[]).
subset_of([X|Xs],Zs):-subset_of(Xs,Ys),maybe_add(X,Ys,Zs).
maybe_add(_,Ys,Ys).
maybe_add(X,Ys,[X|Ys]).
subsets_of(Xs,Xss):-findall(Ys,subset_of(Xs,Ys),Xss).
He then asked us to change it to only give the subsets of some length K (but not by using length/2, by directly finding a recursive definition). My first attempt was to split up the subset_of call into one that adds the extra element and one that does not (instead of having the maybe_add call) and to keep track of the length of the list that was passed and check at the end, but this did not work as planned at all.
subset_of(K, 0, [],[]).
subset_of(K, Len, [X|Xs],Zs):-
L1 is Len - 1,
subset_of(K, L1, Xs, Zs),
L1 == K.
subset_of(K, Len, [X|Xs],Zs):-
L1 is Len - 1,
subset_of(K, L1, Xs,Ys),
do_add(X, Ys, Zs),
Len == K.
subsets_of(K,Xs,Xss):-
length(Xs, Len),
findall(Ys,subset_of(K, Len, Xs,Ys),Xss).
I am NOT asking for the correct code to solve this, but only a push in the right direction so I can keep trying to figure it out. This is my first time with a declarative languange and I am pretty confused.

If you don't want a direct answer, than I'd say that it can be done much simpler. I've got 3 rules in my solution. However I don't use this additional maybe_add formula or anything that resambles it. If you really need it, it can be used and it takes 5 arguments then - 3 input arguments and 2 output arguments. This reduces the number of rules for subset_of to only 2, just as in the original solution. They are quite similar after all.
Also watch out for repetitions. I think subset_of(0, _, []) as suggested in other answer may be a way that leads to repetitions. However there might be a correct solution that incorporates it, I'm not sure that there isn't.
Think of it as a proof of correctness. Say you wanted to prove recursively that one set is a K-element subset of another. How would you go about it. Look at the implications that you used. How can you turn them into Prolog rules?

Not using maybe_add seems like a good idea. However, you don't need two extra arguments: one will do. Your base clause would be
subset_of(0, _, []).
i.e., the empty set is a zero-element subset of anything. Of the two recursive clauses, one would look for K-1-element subsets, the other for K-sized subsets.

Related

counting the elements of a list of lists PROLOG

I am trying to count the elements of a list of
lists.
I implemented the code in this way:
len1([],0).
len1([_X|Xs],N) :- len1(Xs,N1), N is N1+1.
clist([[],[]],0).
clist([Xs,Ys],N):- len1(Xs,N1),len1(Ys,N2),N is N1+N2.
i re-use count element (len1 predicates) in a list, and seems work.
Anyone can say me if is nice work, very bad or can do this but it s preferable other (without len1).
I dont think is good implementation, and otherwhise seems not generic.
Ad example this work only with list, that contain two list inside. If i want make generic? i think need to use _Xs, but i try to change my code and not working.
in particular i try to change this:
clist([Xs,Ys],N):- len1(Xs,N1),len1(Ys,N2),N is N1+N2.
in
clist([_Xs],N):- len1(_Xs,N1),N is N1.
and obviously don't work.
Well you can apply the same trick for your clist/2 predicate: instead of solving the problem for lists with two elements, you can consider two cases:
an empty list [], in which case the total number is of course zero; and
a non-empty list [H|T], where H is a list, and T is the list of remaining lists. In that case we first calculate the length of H, we the calculate (through recursion) the sum of the lists in T and then sum these together.
So we can implement this as:
clist([], 0).
clist([H|T], N) :-
length(H, HN),
clist(T, TN),
N is HN + TN.
The above can be improved by using an accumulator: we can define a predicate clist/3 that has a variable that stores the total number of elements in the list this far, in case we reach the end of the list, we unify the answer with that variable, like:
clist(L, N) :-
clist(L, 0, N).
clist([], N, N).
clist([H|T], N1, N) :-
length(H, HN),
N2 is N1 + HN,
clist(T, N2, N).
Yes, you were correct in wanting to generalize your definition. Instead of
clist([[],[]],0).
(well, first, it should be
clist( [] , 0).
Continuing...) and
clist([Xs,Ys], N):- len1(Xs,N1), len1(Ys,N2), N is N1+N2.
which handles two lists in a list, change it to
clist([Xs|YSs], N):- len1(Xs,N1), len1(YSs,N2), N is N1+N2.
to handle any number of lists in a list. But now the second len1 is misapplied. It receives a list of lists, not just a list as before. Faced with having to handle a list of lists (YSs) to be able to handle a list of lists ([Xs|YSs]), we're back where we started. Are we, really?
Not quite. We already have the predicate to handle the list of lists -- it's clist that we're defining! Wait, what? Do we have it defined yet? We haven't finished writing it down, yes, but we will; and when we've finished writing it down we will have it defined. Recursion is a leap of faith:
clist([Xs|YSs], N):- len1(Xs,N1), clist(YSs,N2), N is N1+N2.
Moreover, this second list of lists YSs is shorter than [Xs|YSs]. An that is the key.
And if the lists were arbitrarily deeply nested, the recursion would be
clist([XSs|YSs], N):- clist(XSs,N1), clist(YSs,N2), N is N1+N2.
with the appropriately mended base case(s).
Recursion is a leap of faith: assume we have the solution already, use it to handle smaller sub-cases of the problem at hand, simply combine the results - there you have it! The solution we assumed to have, coming into existence because we used it as if it existed already.
recursion( Whole, Solution ) :-
problem( Whole, Shell, NestedCases),
maplist( recursion, NestedCases, SolvedParts),
problem( Solution, Shell, SolvedParts).
A Russian matryoshka doll of problems all the way down, turned into solutions all the way back up from the deepest level. But the point is, we rely on recursion to handle the inner matryoshka, however many levels it may have nested inside her. We only take apart and reassemble the one -- the top-most.
howMany([],_,0).
howMany([Head|Tail],X,Times):-
\+(Head = X),
howMany(Tail,X,Times1),
Times is Times1.
howMany([Head|Tail],X,Times):-
Head = X,
howMany(Tail,X,Times1),
Times is Times1 +1.

Prolog and limitations of backtracking

This is probably the most trivial implementation of a function that returns the length of a list in Prolog
count([], 0).
count([_|B], T) :- count(B, U), T is U + 1.
one thing about Prolog that I still cannot wrap my head around is the flexibility of using variables as parameters.
So for example I can run count([a, b, c], 3). and get true. I can also run count([a, b], X). and get an answer X = 2.. Oddly (at least for me) is that I can also run count(X, 3). and get at least one result, which looks something like X = [_G4337877, _G4337880, _G4337883] ; before the interpreter disappears into an infinite loop. I can even run something truly "flexible" like count(X, A). and get X = [], A = 0 ; X = [_G4369400], A = 1., which is obviously incomplete but somehow really nice.
Therefore my multifaceted question. Can I somehow explain to Prolog not to look beyond first result when executing count(X, 3).? Can I somehow make Prolog generate any number of solutions for count(X, A).? Is there a limitation of what kind of solutions I can generate? What is it about this specific predicate, that prevents me from generating all solutions for all possible kinds of queries?
This is probably the most trivial implementation
Depends from viewpoint: consider
count(L,C) :- length(L,C).
Shorter and functional. And this one also works for your use case.
edit
library CLP(FD) allows for
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :- U #>= 0, T #= U + 1, count(B, U).
?- count(X,3).
X = [_G2327, _G2498, _G2669] ;
false.
(further) answering to comments
It was clearly sarcasm
No, sorry for giving this impression. It was an attempt to give you a synthetic answer to your question. Every details of the implementation of length/2 - indeed much longer than your code - have been carefully weighted to give us a general and efficient building block.
There must be some general concept
I would call (full) Prolog such general concept. From the very start, Prolog requires us to solve computational tasks describing relations among predicate arguments. Once we have described our relations, we can query our 'knowledge database', and Prolog attempts to enumerate all answers, in a specific order.
High level concepts like unification and depth first search (backtracking) are keys in this model.
Now, I think you're looking for second order constructs like var/1, that allow us to reason about our predicates. Such constructs cannot be written in (pure) Prolog, and a growing school of thinking requires to avoid them, because are rather difficult to use. So I posted an alternative using CLP(FD), that effectively shields us in some situation. In this question specific context, it actually give us a simple and elegant solution.
I am not trying to re-implement length
Well, I'm aware of this, but since count/2 aliases length/2, why not study the reference model ? ( see source on SWI-Prolog site )
The answer you get for the query count(X,3) is actually not odd at all. You are asking which lists have a length of 3. And you get a list with 3 elements. The infinite loop appears because the variables B and U in the first goal of your recursive rule are unbound. You don't have anything before that goal that could fail. So it is always possible to follow the recursion. In the version of CapelliC you have 2 goals in the second rule before the recursion that fail if the second argument is smaller than 1. Maybe it becomes clearer if you consider this slightly altered version:
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :-
T #> 0,
U #= T - 1,
count(B, U).
Your query
?- count(X,3).
will not match the first rule but the second one and continue recursively until the second argument is 0. At that point the first rule will match and yield the result:
X = [_A,_B,_C] ?
The head of the second rule will also match but its first goal will fail because T=0:
X = [_A,_B,_C] ? ;
no
In your above version however Prolog will try the recursive goal of the second rule because of the unbound variables B and U and hence loop infinitely.

Finding the longest list in Prolog?

I need to write a predicate longestList/2 such that longestList(L1,L2) is satisfied if L2 is the longest
nested list from the list of lists L1.
?- longestList([[1],[1,2],[1,2,3],[1,2,3,4]],LI).
LI = [[1, 2, 3, 4]] ;
No
?- longestList([[a,b,c],[d,e],[f,g,h]],LI).
LI = [[f, g, h],[a,b,c]];
No
Could someone please help me with intuition to go about solving it?
Here's an outline for a basic, recursive approach. Not quite as crisp as the answer #CapelliC gave, but on the same order of simplicity.
The idea is to traverse the list and keep track of the longest list you've seen so far, and what it's length is. Then you step through the list recursively and update these arguments for the recursion if the conditions indicate so. It's a slight elaboration on the technique used to do a recursive "max list element" predicate. To do this, you set up a call to include more arguments (the current longest list, and its length).
longestList([], []).
longestList([L|Ls], LongestList) :-
length(L, Length),
% Start with the first element (L) being my best choice so far
longestList(Ls, L, Length, LongestList).
Here is the expanded predicate with the new arguments.
longestList([L|Ls], LongestListSoFar, GreatestLengthSoFar, LongestList) :-
% Here, you need to examine L and determine if it should supersede
% the longest list so far and its length. You need to keep in mind that
% if the length of L is the same as the max length so far, then I
% may choose to keep the LongestListSoFar, or choose L. Both are
% valid solutions for this call. This is a good place to use the `;`
% operator, and to be cautious about parenthesizing expressions since
% the comma has higher precedence than the semi-colon.
% Also, you'll need to make a recursive call to longestList(Ls, ??, ??, LongestList).
% The arguments to the recursion will depend upon which way the decision flow goes.
%
% After all that to-do, don't let it scare you: it's about 5 lines of code :)
%
longestList([], LongestListSoFar, ??, ??).
% Fill in the ??. What should they be at list's end ([])?
% Do I even care now what the 3rd argument is?
Hopefully that's enough to give you something to think about to make progress. Or, use #CapelliC's solution and write the member_length/3 predicate. :) Note that, as in his solution, the above solution would generate each maximum list on backtracking if there are more than one. So, you could use findall/3 if you want to get all the solutions in one list.
member/2 will allow you to peek an element (a list for your case) from a list: so, if you have a member_length/3 predicate, you could code
longestList(Lists, Longest) :-
member_length(Lists, Longest, N),
\+ ( member_length(Lists, _Another, M), M > N ).
then to find all longest, you can use findall/3...
Following code, which uses if else, seem to work partially. It has to be called with 0 length and so one cannot get length itself from here.
longest_list([H|T], LongList, LongLen):-
length(H, Len),
(Len > LongLen ->
longest_list(T, [H], Len);
longest_list(T, LongList, LongLen)).
longest_list([],Finallist,_):-writeln(Finallist).
?- longest_list([[1,2,3], [3,4], [4,5,6,7,8], [5,3,4]], Longestlist, 0).
[[4,5,6,7,8]]
true.
However, the variable itself is not coming:
?- writeln(Longestlist).
_G1955
true.
It may give some ideas.

Get the length of a list in prolog in a non-recursive way

I have the following code for getting the length of a list in prolog, it works recursively.
Is there any other way for getting the length?
len([], 0).
len([H|T], N) :-
len(T, NT), N is NT + 1.
Any suggestions would be appreciated.
You are asking the wrong question :)
But seriously: the only sensible way of finding the length of a list is to use the built-in length/2. How it is implemented is irrelevant -- more important are its semantics:
?- length([a,b], 2).
true.
?- length([a,b], 4).
false.
?- length([a,b,c], Len).
Len = 3.
?- length(List, 3).
List = [_G937, _G940, _G943].
?- length(List, Len).
List = [],
Len = 0 ;
List = [_G949],
Len = 1 ;
List = [_G949, _G952],
Len = 2 . % and so on
Either way, it doesn't get simpler than that. Any other way of finding the length of a list, or checking for the length of a list, or creating a list of a certain length, or enumerating lists of increasing length is going to be less "simple" than using length/2.
And then: learning Prolog means learning how length/2, and the other nicely declarative built-ins can be used.
Repeating an element N times
Splitting a list into segments of some length
Exactly one pair in a list
Rotate a list
I am sure you can think of many other uses of length/2.
Here is an iterative solution that uses repeat/0 predicate:
getlength(L,N) :-
retractall(getlength_res(_)),
assert(getlength_res(0)),
retractall(getlength_list(_)),
assert(getlength_list(L)),
repeat,
(
getlength_list([]), !, getlength_res(N)
;
retract(getlength_res(V)), W is V + 1, assert(getlength_res(W)),
retract(getlength_list([_|T])), assert(getlength_list(T)), fail
).
This solution creates and retracts facts getlength_res/1 and getlength_list/1 as it walks through the list, replacing the old list with a shorter one, and the old number with a number that is greater by one at each iteration of repeat/0. In a sense, the two dynamically asserted/retracted facts behave very much like assignable variables of imperative languages.
Demo.
In general, iterative solutions in Prolog are harder to read than their recursive counterparts. This should come as no surprise, considering that anything that has an effect of an assignment statement of an imperative programming language goes against the grain with Prolog's design philosophy.
Sorry I could not resist to try out this "challenge":
Input=[a,b,b,b,b,b,b,b,b,a,b,c,d,f], between(1,inf,K),findall( _,between(1,K,_),FreeList), ( FreeList=Input,!,true).
findall/3 is doing the behind-the-scenes recursion, code is making unifications of lists FreeList and Input until they unify

How to count the number of children of parents in prolog (without using lists) in prolog?

I have the following problem. I have a certain number of facts such as:
parent(jane,dick).
parent(michael,dick).
And I want to have a predicate such as:
numberofchildren(michael,X)
so that if I call it like that it shows X=1.
I've searched the web and everyone puts the children into lists, is there a way not to use lists?
Counting number of solutions requires some extra logical tool (it's inherently non monotonic). Here a possible solution:
:- dynamic count_solutions_store/1.
count_solutions(Goal, N) :-
assert(count_solutions_store(0)),
repeat,
( call(Goal),
retract(count_solutions_store(SoFar)),
Updated is SoFar + 1,
assert(count_solutions_store(Updated)),
fail
; retract(count_solutions_store(T))
),
!, N = T.
I can only see two ways to solve this.
The first, which seems easier, is to get all the solutions in a list and count it. I'm not sure why you dislike this option. Are you worried about efficiency or something? Or just an assignment?
The problem is that without using a meta-logical predicate like setof/3 you're going to have to allow Prolog to bind the values the usual way. The only way to loop if you're letting Prolog do that is with failure, as in something like this:
numberofchildren(Person, N) :- parent(Person, _), N is N+1.
This isn't going to work though; first you're going to get arguments not sufficiently instantiated. Then you're going to fix that and get something like this:
?- numberofchildren(michael, N)
N = 1 ;
N = 1 ;
N = 1 ;
no.
The reason is that you need Prolog to backtrack if it's going to go through the facts one by one, and each time it backtracks, it unbinds whatever it bound since the last choice point. The only way I know of to pass data across this barrier is with the dynamic store:
:- dynamic(numberofchildrensofar/1).
numberofchildren(Person, N) :-
asserta(numberofchildrensofar(0)),
numberofchildren1(Person),
numberofchildrensofar(N), !.
numberofchildren1(Person) :-
parent(Person, _),
retract(numberofchildrensofar(N)),
N1 is N + 1,
asserta(numberofchildrensofar(N1),
!, fail.
numberofchildren1(_).
I haven't tested this, because I think it's fairly disgusting, but it could probably be made to work if it doesn't. :)
Anyway, I strongly recommend you take the list option if possible.

Resources