Prolog lists inside the lists - prolog

I'm new to Prolog and what I'm trying to achieve is to define the tower-like type which contains lists of natural numbers. Each "floor" is supposed to have the same amount of "apartments" and I don't know how can I check it.

Assuming with "type" you mean a structure which can hold your data, I suggest using a list of lists, like this:
[[101,102,103],[201,202,203],[301,302,303]]
So now you need to check if each "floor" (sublist), has the same amount of elements. Counting the elements in a list is rather simple:
len([],0).
len([H|T],N1) :-
len(T,N),
N1 is N+1.
Which reads: an empty list [] has 0 elements. A list which can be splittet into a head element H and a rest list T has the length N1, if the length of T is N and N1 is calculated by N+1.
So what is missing? You need to go through all your sublists and get the length of the sublist. If the length of two sublists are different, then fail. If you reach the end with allways the same number, success. So the pattern would look like this:
isHotel(R):-
isHotel(R,_).
Add a placeholder for the counting, actual number of the second argument does not matter at this point.
isHotel([],_) .
If you got to a point where there are no floors left, accept for any number.
isHotel([CurrentFloor|T],N) :-
len(CurrentFloor,N),
isHotel(T,N).
If there are floors left (floorlist can be devided into the current floor CurrentFloor and all floors above T), count the rooms at this floor and go check with the left over floors T. The first time this is runs, the number N of rooms will be calculated and forwarded to every other call - therefore for the first time the calculation is just a calculation, in every other ecxecution it is a check as well. This leads to rejects if two lusts do not match in size. Please note this code does not check if the input is a list of lists of numbers.
Checked with SWISH:
?- isHotel([[101,102,103],[201,202,203],[301,302,303]]).
true.
?- isHotel([[101,102,103],[201,202,203],[301,302,3,03]]).
false.
?- isHotel([]).
true.

Related

Understanding this bubble sort solution in Prolog

How does this bubble sort solution work in Prolog?
bubblesort([], []).
bubblesort([H], [H]).
bubblesort([H|D], R) :-
bubblesort(D, E),
[B|G] = E,
( (H =< B, R = [H|E])
; (H > B, bubblesort([B,H|G], R))
).
Here is an example trace: https://pastebin.com/T0DLsmAV
I understand the the line bubblesort(D,E), is responsible for sorting it down to one element, but I don't understand how this works. I understand the basics of lists in prolog, but still cannot work out how this solution operates.
The main difficulty with this code is that bad variable names were chosen and are making the logic harder to follow than it needs to be.
The first two cases are obviously base cases. The first says "the empty list is already sorted" and the second says "a singleton list is already sorted." This should make sense. The third case is where things get interesting.
Let's examine the first part.
bubblesort([H|D], R) :-
bubblesort(D, E),
All that's happened so far is we've named our result R and broken our inputs into a first element H and a tail D. From there, we have said, let's bubblesort the tail of our input and call that E. Maybe this would be a little easier to follow?
bubblesort([H|T], Result) :-
bubblesort(T, TSorted),
Next up,
[B|G] = E,
Again, bad names, but what the author is intending to do here is straightforward: take apart the result of sorting the tail so we can talk about whether the next item in the sorted tail is the right element for that position, or if it needs to switch places with the head of our input. Let's rename:
[HeadOfTSorted|RestOfTSorted] = TSorted,
Now we have a condition. Think of it in terms of prepending onto a sorted list. Say you have some element, like 3, and I hand you a sorted list. You want to determine if your 3 goes at the front or somewhere else. Well, suppose I gave you a sorted list that looked like [5,7,19,23,...]. You'd know that your 3 is right where it needs to be, and you'd hand back [3,5,7,19,23,...]. That's exactly the first case of the condition:
( (H =< HeadOfTSorted, Result = [H|TSorted])
Now consider another case, where I hand you a list that starts with [1,2,...]. You know you can't just put the three at the start and give me back [3,1,2,...]. But you don't really know where the 3 goes; it just doesn't go at the start. So what you have to do is resort the rest of the list with the 3 at the start, after the 1: [1 | resorted([3,2,...])]. That's effectively the other branch of the condition:
; (H > HeadOfTSorted, bubblesort([HeadOfTSorted,H|RestOfTSorted], R))
).
Hope this helps!
note: the key to recursive problem solving is exactly not to think about the minutiae of our code's operations. Imagine you already have the solution, then just use it to solve a smaller subproblem, thus arriving at the full problem's solution.
Your code, with more suggestive variable names so I could follow it, reads:
bubblesort([], []). % empty list is already sorted
bubblesort([H], [H]). % singleton list is already sorted
bubblesort([H|T], S) :- % `[H|T]` sorted is `S`, *if*
bubblesort(T, [M|R]), % `T` sorted is `[M|R]`, *and*
( % *either*,
H =< M, % in case `H` is not greater than `M`,
S = [H,M|R] % `S` is `[H,M|R]`,
; % *or*
H > M, % in case `H` is greater than `M`,
bubblesort([M,H|R], S) % `S` is `[M,H|R]` sorted by the same algorithm
).
(H is for "head", T is for "tail", S is "sorted", R "rest" and M is "minimum" -- see below for that).
We prove its correctness by structural induction. The induction hypothesis (IH) is that this definition is correct for shorter lists. We need to prove it is then also correct for a longer list. Indeed T is one-element shorter than [H|T]. Thus IH says [M|R] is sorted. This means M is the minimum element in T. It also means T is non-empty (sorting doesn't change the number of elements), so the clauses are indeed mutually-exclusive.
If H is not larger than the minimum element in T, [H,M|R] is obviously sorted.
Otherwise, we sort [M,H|R]. M is the minimum element and thus guaranteed to be the first in the result. What's actually sorted is [H|R], which is one element shorter, thus by IH sorting it works. QED.
If the last step sounds fishy to you, consider replacing the second alternative with the equivalent
; H > M, % in case `H` is greater then `M`,
bubblesort([H|R], S1), % `S1` is `[H|R]` sorted by the same algorithm
S = [M|S1]
).
where the applicability of the induction step is even clearer.
I'm not so sure it's a bubble sort though.
update: Indeed, measuring the empirical orders of growth, its number of inferences grows as ~ n3 (or slower), but true bubble sort clocked at ~ n2.1 (close enough to the theoretical ~ n2), where n is the list's length:
tbs([], []). % 'true' bubble sort
tbs([H],[H]).
tbs(L,S):- bubble(L,B),
( L==B -> S=L ; tbs(B,S) ).
bubble([],[]).
bubble([A],[A]).
bubble([A,B|C],R):-
( A =< B -> bubble([B|C],X), R=[A|X]
; bubble([A|C],X), R=[B|X] ).

How to compare lists length Prolog

I'm new at Prolog and i was trying to solve some exercises and I found this one twice_as_long(L1,L2) that succeeds if the list L2 is twice as long as the list L1.
Do NOT compute the lengths of the lists.
twice_as_long([],[]).
true.
?- twice_as_long([a],[1,2]).
true.
?- twice_as_long([a,b],X).
X = [_G328, _G331, _G334, _G337] ;
false
I want some hint please cuz i don't want to compare lengths like what they said .
We can generalize your second example as a rule:
twice_as_long([_],[_,_]).
But we can do better:
twice_as_long([_|T1], [_,_|T2]) :- twice_as_long(T1,T2).
That, with the base case from you first example, will do the job.
With respect to Prolog conventions, given a predicate of the form type_of_relationship(X,Y), it's pretty customary to read it as a declaration of fact along the lines of
X has a type_of_relationship with Y.
So, let's flip the order of the arguments: twice_as_long(X,Y) asserts that X is twice as long as Y.
Given that, and amplifying the answer from #ScottHunter, Let's break things down into simple cases.
First, your example shows a case that should fail as succeeding.
twice_as_long([],[]).
asserts that the empty list is twice as long as itself, something that is manifestly untrue: the empty list is of length zero and twice zero is still..zero. So that case should be discarded.
There is, however, the simplest case possible:
twice_as_long( [_,_] , [_] ) .
an assertion that a list of length 2 is twice as long as a list of length 1.
Then, there is the generic case:
twice_as_long( [_,_|Xs] , [_|Ys] ) :-
twice_as_long(Xs,Ys) .
in which we say that a list of 2 or more items is twice as long as a list of 1 or more items...
IF, the remainder of the first list is twice as long as the remainder of the second list, where the remainders are obtained by removing the first 2 items from the first list and just 1 item from the second list.
That gives us this as the solution:
twice_as_long( [_] , [_,_] ) .
twice_as_long( [_|Xs] , [_,_|Ys] ) :- twice_as_long(Xs,Ys) .
The predicate will succeed when you get to the simple base case, and fail otherwise.

Generating a list in prolog

Hello I want to make a program in Prolog, that given a list of numbers and a number, it appends all the concurences of position of the number in a second list.
For example for the list (5,10,4,5,6,5) and number =5 the new list should be
(1,4,6)
here is my code so far
positions(X, [X|_],1).
positions(X, [P|T], N) :- positions(X, T, N1), N is N1+1.
find(X, [H|T] ,Z) :-positions(X,[H|T],N) , append([],N,Z).
the positions returns the first concurrence of X in the list, but I don't know how to proceed. Can you help me?
If it's not an assignment, then you can benefit from using the built-ins findall/3 and nth1/3:
?- findall(Nth, nth1(Nth, [5,10,4,5,6,5], 5), Nths).
Nths = [1, 4, 6].
Taking just the nth1 phrase, and running that, you can see it is backtracking and finding multiple solutions, then we just use findall to collect them into a list.
?- nth1(Nth, [5,10,4,5,6,5], 5).
Nth = 1 ;
Nth = 4 ;
Nth = 6.
nth1/3, when using a variable for the first parameter, is saying 'give me a list index where where the 3rd parameter is found in the list of the second parameter.
You have some good ideas, but I would suggest a couple things:
1) In Prolog, it can be beneficial to give variables meaningful names
2) Use an accumulator and you will only need positions and append
3)Use a different base case
positions([Num|List],Num,[Index|SubResult],Index) :- Index2 is Index+1,
positions(List,Num,SubResult,Index2).
positions([NotNum|List],Num,Result,Index) :- NotNum \= Num,
Index2 is Index+1,
positions(List,Num,Result,Index2).
positions([],Num,[],Index).
In our first general case, we can see the numbers match, so we go find how many results are in our sublist, which we will call the SubResult and then push the current index on to our SubResult
The next general case, the numbers do not unify, and our Result IS the SubResult, so let's call them the same thing.
In our final case (the base case) we can see the list is empty, in this case we return an empty list as we cannot match against an empty list.
You can see that the above rules are order-independent, which is something very valuable in Prolog. This means you can arrange the rules in any order, and the semantics of your Prolog program remain unchanged. Using unification to achieve this will prevent future pain in debugging.
We can wrap our predicate in the following way
positions(Num, List, Positions) :- positions(List, Num, Positions, 1).
This will allow for queries of positions(5,[5,10,4,5,6,5],Positions).

Counting the number of lists in a nested list

I am having troubles counting the number of lists in a nested list.
count_lists([H|T],R):-
atomic(H),!,
count_lists(T,NR),
R is NR+1.
count_lists([[H|T]|Rest],R):-
!,
count_lists([H|T],R1),
count_lists(Rest,R2),
R is R1+R2.
count_lists([],0).
First of all, I try the basic case where an element in the list is atomic and thus, I should increment the counter by one. (Also, I tried removing the atomic predicate because I figured that because of it, my code will compute the number of elements in a nested list, but it still doesn't work)
Then, if the first element is a list itself, I go recursively on it and on the remaining list, adding the results.
And the third clause is states that the number of nested lists in an empty list is 0.
?count_lists([[1,5,2,4],[1,[4,2],[5]],[4,[7]],8,[11]],R).
should return 8 but instead, returns 12.
I know it's been a while since you asked this, but here is the answer I think you were looking for:
count_lists([],1).
count_lists([H|T],Rez):-atomic(H),!,count_lists(T,Part),Rez is Part.
count_lists([H|T],Rez):-count_lists(H,Part1),count_lists(T,Part2),Rez is Part1+Part2.
This way, you count only the number of lists and not the number of elements within.
you need to distinguish lists from other elements, i.e.
count_lists(E,R):-
is_list(E),!,count_elems(E,N),
R is N+1.
count_lists(_,0).
count_elems([H|T],R):-
count_lists(H,Hc),
count_elems(T,Tc),
R is Hc+Tc.
count_elems([],0).
but the code is contrived, using library we can get it done in 1 step:
count_lists(E, R):-
maplist(count_lists, E, Cs) -> sum_list(Cs, S), R is S+1 ; R = 0.
the code can be understood only WRT maplist/N behaviour
?- maplist(_,a).
false.
?- maplist(_,[]).
true.
?- maplist(_,[1]).
ERROR: apply:maplist_/2: Arguments are not sufficiently instantiated
In your solution you forget that e.g. [1,2,3] = [1,2,3| []] or [1,2,3] = [1| [2| [3| []]]]. Thus, you're "over-counting", thanks to your first clause. For example:
?- count_lists([1,2,3], N).
N = 3.
But there's another problem. In your second clause, if you've a nested list that nests other lists, you don't count it. Not clear from the title if that's intended or if it's a bug.
You shouldn't have complicated yourself.
count([],1).
count([L1|L2],Rez):- count(L1,Rez1),count(L2,Rez2),Rez is Rez1+Rez2.
You take out all the elements in a list recursively until you are left out with the empty list which values 1.

Prolog compare list elements to Head element

I have predicate which shows all numbers which are smaller than 10.
small([H|T],H):- H=<10.
small([_|T],X):-small(T,X).
It is quite simple. But how should I change it so that I could compare every next item to the first element?
For example, ?- small([4,2,3,9,1,0,12],X). would show X=2;X=3;X=1;X=0 ?
You can split the problem in two procedures, one that takes the first element and then applies the recursion over the remaining elements of the list and checks whether each item is less than or equal to the first element:
small([M|T],X):- small1(T, M, X).
small1([H|_], M ,H):- H =< M.
small1([_|T], M, X):- small1(T, M, X).

Resources