Related
I'm writing a predicate for finding the bigger number in pairs. If the number has no pair - it will be just added.
write_list([A|[]]):- write(A).
write_list([A, B|Tail]) :- ((A>B, write(A));(A<B,write(B))), nl,
write_list([B|Tail]).
My problem is, I cannot figure out how to write a result in another list instead of printing the result out:
write_list([1,2,6,8,5], X).
X = [2,6,8,8,5].
write only prints the content to the standard output, it does not "yield" it to the result list. In Prolog the only way to generate values, is through unification.
You thus need to define a predicate maxpair/2, not write_list/1.
The predicate thus looks like:
:- use_module(library(clpfd)).
maxpair([A], [A]).
maxpair([A, B|Tail], [H|T]) :-
H #= max(A, B),
maxpair([B|Tail], T).
The first clause says that the maxpair/2 of a singleton list is that singleton list. The latter says that the maxpair/2 for a list containing two or more lists is a list that starts with the maximum of the first two elements, and we recurse on the tail of the list.
The above can also yield a list in reverse. For example:
?- write_list(L, [5, 3, 2, 1]).
L = [5, 3, 2, 1] ;
false.
?- write_list(L, [1, 4, 2, 5]).
false.
?- write_list(L, [3, 3, 5, 5]).
L = [_542, _548, _554, 5],
_542 in inf..3,
3#=max(_542, _548),
_548 in inf..3,
3#=max(_548, _554),
_554 in inf..3 ;
false.
?- write_list(L, [3, 5, 5, 4]).
L = [_1128, _1134, 5, 4],
_1128 in inf..3,
3#=max(_1128, _1134),
_1134 in inf..3 ;
false.
So depending on the situation it can:
fully reconstruct the list;
construct a list with some variables with intervals; or
proof that it is impossible to construct such a list.
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).
I've been trying to solve this problem for quite sometime and I think the logic I'm attempting is flawed.
The objective is to replace a subsequently decreasing sublist of numbers by the last of the sublist.
?- compare([1, 3, 7, 6, 5, 10, 9], Result).
Result = [1, 3, 5, 9] ;
false.
What I tried was:
compare([A,B|T],X):-
%succ(B,A),
A is B+1,
append([],NextX,X),
compare([B|T],NextX).
remove([A,B|T],X):-
A=\=B+1,
compare([B|T],X).
I'm not certain how to write the base case for the compare/2 and I think the I'm not correctly converting my logic into the code. What I'm trying here is to compare A and B and drop A from the list if they are successive numbers.
Your help is very much appreciated.
You are almost there. First cover the special case: If the list contains only one element it is in the list.
compare([X],[X]).
your second rule just needs little altering:
compare([A,B|T],X):- % A is not in the list if
A is B+1, % A = B+1
compare([B|T],X). % Note: X is the same as in head of rule
Your predicate remove/2 is should be the 3rd rule of compare/2 covering the alternative case:
compare([A,B|T],[A|X]):- % A is in the list
A=\=B+1, % if A is not B+1
compare([B|T],X).
Now the query works:
?- compare([1, 3, 7, 6, 5, 10, 9], Result).
Result = [1,3,5,9] ?
yes
However, this predicate only works if the first list is variable free. You can't use it the other way round:
?- compare([A,B,C], [1,2]).
ERROR at clause 2 of user:compare/2 !!
INSTANTIATION ERROR- X is A+B: expected bound value
If you use library(clpfd) on the other hand ...
:- use_module(library(clpfd)).
compare([X],[X]).
compare([A,B|T],X):-
A #= B+1,
compare([B|T],X).
compare([A,B|T],[A|X]):-
A #\= B+1,
compare([B|T],X).
... the above query works too:
?- compare([A,B,C], [1,2]).
A = C = 2,
B = 1 ? ;
A = 1,
B = 3,
C = 2 ? ;
no
I am creating a sequence as a [Integer] in Haskell. The mathematical definition of the sequence is such that it repeats for some positive integers. In such a situation, I want to terminate the sequence and determine the length of the finite list.
My attempt at a solution is to first create an infinite list from the mathematical sequence. Then I want to filter the list for all elements until the first element repeats. The result should not include the repeating head of the list.
I have two questions/concerns here:
1) How do I match the head of the list to an element later in the list?
2) Is this an efficient method of solving my problem? (I will add more details about the exact sequence later if needed. For now I am looking for general comments.)
The algorithm that you described can simply be implemented like this:
findPeriodic :: Eq a => [a] -> [a]
findPeriodic [] = error "there are no periodic sequences in the empty list"
findPeriodic (x : xs) = x : takeWhile (/= x) xs
It does exactly what you describe: it takes the head of some list, and collects the part of the list up until that head element appears again in the list. So, for example:
list = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, ...]
findPeriodic list => [1, 2, 3, 4, 5]
The first element might never repeat in a sequence like 1,2,3,4,5,3,4,5,3,4, ... , where (a !! i) == (a !! j) ==> (a !! (i+1)) == (a !! (j+1)) (like you added in a comment, which is different from what you've asked for in the question).
This is known as cycle detection and was recently discussed e.g. here.
I have a function that outputs names that fit a specific constraint. This function is fine.
But I need to use that function to make another function that turns the outputs of the former function into a list. Being a complete beginner with Prolog, I have no clue how to do this.
My problem is that I don't know how to iterate over the outputs to append it to an accumulator. The function which outputs names does so, then I press ";" or SPACE and it outputs the next answer until it's out of answers. I figure this means I have to make multiple calls to the function then append it. But I don't know how many times I need to call it, since I can't iterate over it like a list with [Head|Tail].
Here's what I have so far(although it's probably wrong):
%p1(L,X) determines if chemicals in List X are in any of the products and stores those products in L
p1(L,X) :- p1_helper(L,X,[]).
p1_helper(L,X,Acc) :- has_chemicals(A,X),append(Acc,[A],K),L=K, p1_helper(L,X,K).
function that outputs names with query has_chemicals(X,[List of Chemicals]).:
%has_chemicals(X,Is) determines if the chemicals in List Is are in the chemical list of X.
has_chemicals(X,Is) :- chemicals(X,Y), hc(Y,Is).
%hc(X,Y) determines if elements of Y are in elements of X.
hc(Y,[]).
hc(Y,[C|D]) :- isin(C,Y), hc(Y,D).
Any help is appreciated.
But I need to use that function to make another function that turns the outputs of the former function into a list. Being a complete beginner with Prolog, I have no clue how to do this.
findall(+Template, :Goal, -Bag):
Creates a list of the instantiations Template gets successively on backtracking over Goal and unifies the result with Bag.
For example, how to collect all odd numbers from 1 to 15:
odd( X ) :-
X rem 2 =:= 1.
We can get all that odds one-by-one.
?- between( 1, 15, X ), odd( X ).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9 ;
X = 11 ;
X = 13 ;
X = 15.
And we can collect them into a list:
?- findall(X, (between( 1, 15, X ), odd( X )), List).
List = [1, 3, 5, 7, 9, 11, 13, 15].
I think you are looking for a way to capture the output of isin/2. Then you can use the builtin with_output_to/2, and combine it with findall/3, as suggested by other answers.
I encourage you to visit this page especially if you use swi-prolog.
There are 4 predicates that do what you want : findall/3, findall/4, bagof/3 and setof/3.
To summarize, here is the test predicate I'll be working with :
test(0, 3).
test(1, 3).
test(2, 5).
test(3, 4).
First, the simplest, findall/3 and findall/4 :
?- findall(C, test(X, C), Cs).
Cs = [3, 3, 5, 4].
?- findall(C, test(X, C), Cs, TailCs).
Cs = [3, 3, 5, 4|TailCs].
They just return all the alternatives, with duplicates, without sorting, without binding the other free variables, as a normal list for findall/3 and difference list for findall/4. both findalls predicates succeed when the list is empty.
Then, bagof. Basically, bagof/3 works as findall/3 but binds free variables. That means that the same query than above but with bagof/3 returns :
?- bagof(C, test(X, C), Cs).
X = 0,
Cs = [3] ;
X = 1,
Cs = [3] ;
X = 2,
Cs = [5] ;
X = 3,
Cs = [4].
By telling bagof/3 not to bind all the free variables, you obtain findall/3 :
?- bagof(C, X^test(X, C), Cs).
Cs = [3, 3, 5, 4].
Still you have to note that bagof/3 fails when the result is empty, where findall/3 doesn't.
Finally, setof/3. It's basically bagof/3 but with the results sorted and no duplicates :
?- setof(C, X^test(X, C), Cs).
Cs = [3, 4, 5].