Related
I'm new to Prolog, and struggling to do the following:
I need to write a predicate which outputs the number of list elements inside a list of lists, and output the answer itself as a list.
As an example, I would want:
clistoflists([[a,b,c,d],[e,f,g],[h,i][j,k,l]], N).
N = (4,3,2,3)
I am able to write a predicate to count the elements of a simple list:
count_list([],0).
count_list([_|T], C) :- count_list(T, CNT), C is CNT + 1.
I'm just very unsure how to proceed with the more complicated list of lists, and especially providing for the desired output list.
Any guidance would be very welcome. I've been toying with this for far too long.
The simplest solution is to use the predicates length/2 and maplist/3 as follows:
?- maplist(length, [[a,b,c,d],[e,f,g],[h,i],[j,k,l]], L).
L = [4, 3, 2, 3].
Another alternative is to create your own versions of those predicates:
maplen([], []).
maplen([X|Xs], [Y|Ys]) :-
len(X, Y),
maplen(Xs, Ys).
len([], 0).
len([_|Xs], N) :-
len(Xs, M),
N is M + 1.
Example:
?- maplen([[a,b,c,d],[e,f,g],[h,i],[j,k,l]], L).
L = [4, 3, 2, 3].
I am having a bit of trouble with prolog as I have just started learning it. I am unsure how to test if X is the median of A, B, C. My first thought was to make a list of A, B, C and then sort it. I would then check if X is equal to the second number. The problem being that I don't know how to take three values and turn them into a list (If you can). Is this even the most effecent way to do this? Honestly I have no Idea so any insite would be helpful.
this is a very basic solution, with a sorting only accepting 3 values, but it should make the problem solved.
is_median_of_sorted([_, ValueToCheck, _],ValueToCheck).
sorted_list_of_3([A,B,C],R) :-
A>B, A>C, B>C, R = [A,B,C];
A>C, A>B, C>B, R = [A,C,B];
B>A, B>C, A>C, R = [B,A,C];
B>C, B>A, C>A, R = [B,C,A];
C>A, C>B, A>B, R = [C,A,B];
C>B, C>A, B>A, R = [C,B,A].
is_median_of_3(List, ValueToCheck) :-
sorted_list_of_3(List,SortedList),
is_median_of_sorted(SortedList, ValueToCheck).
To check it, query:
is_median_of_3([1,10,4],4).
Or if you want to check what is the median of a given list:
is_median_of_3([1,10,4],X).
You can also check it via browser at: https://swish.swi-prolog.org/p/three_values_median.pl
What is does is : is_median_of_3 first gets a matching sorted list, and then checks agains is_median_of_sorted, which just picks a 2nd element of the list.
Hope I could help.
If you want to create a modular program, you had to insert all the elements in a list, sort it and find the median. This could be done in this way:
findMedian([H|_],0,H):- !.
findMedian([_|T],C,X):-
C1 is C-1,
findMedian(T,C1,X).
median(L,X):-
msort(L,SortedL),
length(SortedL,Len),
Len2 is Len//2,
findMedian(SortedL,Len2,X).
?- median([1,10,4,5,7],X).
X = 5
?- median([1,10,4,5,7],5).
true
This solution will works also with list with an even number of elements, returning the element after the middle of the list (ex. 4 elements, [0,1,2,3], it returns 2). In this case you have to decide what to do (fail, return the two elements in the middle ecc...)
EDIT: as suggested in the comment, you should use msort/2 instead sort/2 because sort/2 removes duplicated elements.
I would choose a solution similar to #damianodamiano's, but I would find the middle element of a list without using length/2:
median(List, Median) :-
msort(List, SortedList),
middle_element(SortedList, SortedList, Median).
middle_element([], [M|_], M).
middle_element([_], [M|_], M).
middle_element([_,_|Xs], [_|Ys], M) :-
middle_element(Xs, Ys, M).
A simple answer to "check if X is the median of A,B,C?" is:
is_median_of_3(A,B,C,X):-
msort([A,B,C],[_,X,_]).
This will try to match if [A,B,C] sorted consists of any list (of three elements) with X as the middle element.
I don't know everywhere, but in swish there are residuals coming out from msort as such:
msort([2,8,4],L).
L = [2, 4, 8],
_residuals = []
L = [2, 4, 8],
_residuals = [_1080]
L = [2, 4, 8],
_residuals = [_1122, _1128]
L = [2, 4, 8],
_residuals = [_1170, _1176, _1182]
L = [2, 4, 8],
_residuals = [_1224, _1230, _1236, _1242]
L = [2, 4, 8],
_residuals = [_1284, _1290, _1296, _1302, _1308]
L = [2, 4, 8],
_residuals = [_716, _722, _728, _734, _740, _746]
L = [2, 4, 8],
_residuals = [_788, _794, _800, _806, _812, _818, _824]
L = [2, 4, 8],
_residuals = [_866, _872, _878, _884, _890, _896, _902, _908]
and so on...
Also, I couldn't test it in tutorialspoint because it seems broken.
Following a generate & test approach you can write:
median(List,Median) :-
dif(List,[]), msort(List,SList), length(List,Len),
append(Low,[Median],Tmp), append(Tmp,High,SList),
length(Low,LowLen), div(Len,2)=:=LowLen, !.
This has a convenient declarative reading: Median is the value of a non-empty List that splits the sorted version SList of List into two halves Low and High, viz. Median is the "middle element" of the distribution of the values in List.
Indeed, the program above determines Median by checking whether SList can be written as a list concatenation Low + [Median] + High such that the length of Low is half the length of SList. Since High is never used (i.e. it is a singleton), the program can be rewritten by substituting it with _ as in:
median(List,Median) :-
dif(List,[]), msort(List,SList), length(List,Len),
append(Low,[Median],Tmp), append(Tmp,_,SList),
length(Low,LowLen), div(Len,2)=:=LowLen, !.
Naturally, it is also possible to distinguish the case in which the length of the list is odd from the case it is even, so to return the average of the two median elements in the latter case:
median(List,Median) :-
is_list(List), dif(List,[]),
msort(List,SList), length(List,Len),
median(SList,Len,Median).
median(SList,Len,Median) :-
Len mod 2 =:= 1,
append3(Low,[Median],_,SList),
length(Low,LowLen), div(Len,2)=:=LowLen, !.
median(SList,Len,Median) :-
Len mod 2 =:= 0,
append3(Low,[M1,M2],_,SList),
length(Low,LowLen), div(Len,2)=:=LowLen + 1,
Median is (M1+M2)/2, !.
append3(L1,L2,L3,L) :- append(L1,L2,T), append(T,L3,L).
The example is like this
?- runs([3,4,5,4,2,7,5,6,6,8,3], RunList).
RunList = [[3, 4, 5], [4], [2, 7], [5, 6, 6, 8], [3]]
The list need to be broken in to a number of non-decreasing sequence of consecutive numbers. My code is:
next([],0).
next([H|_],R):-
R is H.
runs1([],[]).
runs1([H|T],R):-
runs1(T,R1),
next(T,X),
H=<X,
R = [H|R1].
runs1([H|T],R):-
runs1(T,R1),
next(T,X),
H>X,
R = [[H]|R1].
I tried lots of methods, but still do not know how to write it...
Hope someone could help me.
Thanks in advance.
For a logically pure and monotone implementation look at
my answer to related question "Extracting sequences (Lists) Prolog".
I present the meta-predicate splitlistIfAdj/3 which is based on if_/3 as proposed by #false in this answer.
splitlistIfAdj/3 ensures logical soundness while remaining deterministic when possible.
The predicate passed to splitlistIfAdj/3 has to obey the same convention as (=)/3 and memberd_truth/3.
For your case we need a definition of (#>)/3:
#>(X,Y,Truth) :- X #> Y #<==> B, =(B,1,Truth).
Let's use splitlistIfAdj/3 and (#>)/3 in the example you gave:
?- splitlistIfAdj(#>,[3,4,5,4,2,7,5,6,6,8,3],Pss).
Pss = [[3,4,5],[4],[2,7],[5,6,6,8],[3]]. % succeeds deterministically
Now let's ask a more general query:
?- splitlistIfAdj(#>,[A,B],Pss).
Pss = [[A],[B]], A#>=_X, B+1#=_X ;
Pss = [[A,B]], A#>=_Y#<==>_Z, B+1#=_Y, _Z in 0..1, dif(_Z,1).
Last, let's run the query that #lurker suggested in his comment to #rrrfer's answer:
?- splitlistIfAdj(#>, Ls, [[3,4,5],[4],[2,7],[5,6,6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ;
false.
runs([], []):-!.
runs([H|T], S):-
runs(T, TS),
ins(H, TS, S).
ins(E, [], [[E]]):-!.
ins(E, [[H|T]|TL], [[E, H|T]|TL]):-
H >= E, !.
ins(E, TL, [[E]|TL]).
Hi I want to write a function called perfect_part that takes a list of integers as input and if possible, return two sub-lists whose sum is exactly half of the total values of all integers in original list.
For example,
?- perfect_part([6, 3, 2, 1], L, R).
L = [6],
R = [3, 2, 1] ;
false.
?- perfect_part([1, 2, 3, 4, 0], L, R).
L = [1, 4],
R = [2, 3, 0] ;
L = [2, 3],
R = [1, 4, 0] ;
Here is my try:
listsum([], 0).
listsum([H|T], Total):-
listsum(T, Sum1),
Total is H + Sum1.
subset([],L).
subset([X|T],L):- member(X,L),subset(T,L).
perfect_part([], 0, 0).
perfect_part(Nums, Left, Right):-
listsum(Nums, S),
H is S / 2,
subset(Left, Nums),
subset(Right, Nums),
listsum(Left, H),
listsum(Right, H).
But if I run it, I got error message:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I fix it? Am I on the right track to sovle this problem?
The predicate subset/2 is missing, and it's an essential part to answer your question. Specifically, if sublists are contiguous, you can solve as easily as
perfect_part(X,L,R) :- append(L,R,X), listsum(L,S), listsum(R,S).
Then I would look for a more adequate replacement for append/3, like
partition([],[],[]).
partition([H|T],[H|L],R) :- partition(T,L,R).
partition([H|T],L,[H|R]) :- partition(T,L,R).
that leads to
perfect_part(X,L,R) :- partition(X,L,R), listsum(L,S), listsum(R,S).
edit Now, from subset/2 it's apparent the error cause: in base case, L is unbound.
Should be subset([],[])., but it doesn't terminate. I wonder how you get the error...
more edit To avoid duplicate solutions, I suggest to break the symmetry with
perfect_part(X,L,R) :- partition(X,L,R), L #=< R, listsum(L,S), listsum(R,S).
permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).
If I type permutation([1,2,3],R), the first solution is "[1,2,3]" but how to get to the second one without using ";" or "fail". I need to use the 2nd solution like "[1,3,2]" or so in order compare it to another list.
What I mean is:
permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).
go_perm(L,P) :-
L = P,
write(P),nl.
go_perm(L,P) :-
permutation(P,P2), % in this case i wanna get the next solution -.-
go_perm(L,P2).
If L = P then it finishes. Permutation of the first solution for "[1,2,3]" is "[1,2,3]". But that pulls me into stackoverflow because it runs into never-endless thing.
Perhaps you understand me. Thanks!
Assuming you want to loop over the solutions to print them
One standard way to accomplish this is to fail and backtrack, as in:
print_all_permutations(X)
:- permutation(X, Y), print(Y), nl, fail ; true.
Assuming you just want to check if a given solution is correct
You are already done. Just call the function with the reference list and the list you want to test:
permutation([1, 2, 3], [2, 1, 3]).
will return true, because [2, 1, 3] is a permutation of [1, 2, 3]. If the second argument is not a permutation, the goal will evaluate to false.
This is the magic of prolog: finding a solution, or checking if a given solution is correct, are the same thing.
In between: partial solution
The same reasoning still applies:
permutation([1, 2, 3], [2, X, 3]).
will display the only possible value for X.
Or, if you want the whole list to be the result:
X = [2, X, 3], permutation([1, 2, 3], X).
You need to look at various aggregate predicates. Here, findall would work nicely. you can invoke it:
ListIn=[1,2,3], findall(Perm, permutation(ListIn, Perm), Permutations).
This will call permutation on ListIn until it fails. Each Perm returned by permutation will be collected into the Permutations variable.
permutation is a predicate that succeeds when one list is a permutation of the other. You don't actually need to enumerate them; just write permutation([1, 2, 3], [2, 1, 3]) and Prolog will tell you "true".