PROLOG - LCM of couples in list - prolog

I want to find the Least Common Multiple (LCM) of couples from a list. But in the following way:
For example if I have this list:
L1 = [1,2,3,4,5].
I want to produce this list:
L2 = [1,2,6,12,60].
I use the first element of L1 as first element of L2 and the rest follow this form:
L2[0] = L1[0]
L2[i+1] = lcm( L1[i+1] , L2[i] )
Here is what I've done so far, but it doesn't work. Always printing false.
%CALL_MAKE----------------------------------------
%Using call_make to append Hd to L2 list
call_make([Hd|Tail], Result) :-
make_table(Tail, [Hd], Result).
%MAKE_TABLE---------------------------------------
%Using make_table to create the rest L2
make_table([],Res,Res).
make_table([Head|Tail], List, Result) :-
my_last(X, List),
lcm(Head, X, R),
append(List, R, Res),
make_table(Tail, Res, Result).
%last element of a list---------------------------
my_last(X,[X]).
my_last(X,[_|L]):- my_last(X, L).
%GCD----------------------------------------------
gcd(X, 0, X) :- !.
gcd(X, Y, Z) :-
H is X rem Y,
gcd(Y, H, Z).
%LCM----------------------------------------------
lcm(X,Y,LCM):-
gcd(X,Y,GCD),
LCM is X*Y//GCD.
I want to run the program and get this:
?- call_make([1,2,3,4,5], Result).
Result = [1,2,6,12,60].

append/3 is taking two lists to concatenate, while here:
append(List, R, Res),
R is a scalar. Change it to
append(List, [R], Res),

Related

Prolog How to write a predicate sum 3 max values in list?

How to write a predicate sum 3 max values in list?
max3(L,X)
Example:
max3([1,7,9,3,5],X).
X = 21.
As a starting point:
% Can potentially change order of the list in Rest
list_max_rest([H|T], Max, Rest) :-
list_max_rest_(T, H, Max, Rest).
list_max_rest_([], Max, Max, []).
list_max_rest_([H|T], P, Max, [P|Rest]) :-
H #> P,
!,
list_max_rest_(T, H, Max, Rest).
list_max_rest_([H|T], P, Max, [H|Rest]) :-
list_max_rest_(T, P, Max, Rest).
Usage:
?- list_max_rest([2,1,200,9], Max, Res).
Max = 200,
Res = [1, 2, 9].
Use that 3 times...
max3(Ls, X) :-
select(A, Ls, Ls2),
select(B, Ls2, Ls3),
select(C, Ls3, Ls4),
A >= B,
B >= C,
\+ (member(Q, Ls4), Q > C),
X is A+B+C.
Take A from the list, B from the remainder, C from that remainder, they must be A>=B>=C, and there must not be a member Q left in the remainder which is bigger than C. Add those up.
This is not efficient; brebs' suggestion of:
max3(Ls, X) :-
sort(0, #>=, Ls, [A,B,C|_]),
X is A+B+C.
is neater

Build a new list of elements which appears more than 3 times in old list in Prolog

My main task - build a new list of elements (numbers) that appear in the old list more than three times.
Asking query: res([1,2,2,3,3,3,4,4,4,4,5,5,5,5,5],X).
Expected result: X = [4, 5]
I have a code that counts the number of occurrences of each number:
count(_, [], 0).
count(Num, [H|T], X) :- dif(Num,H), count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
res(A, X) :- findall(X,count(_,A,X),X).
But it works little bit wrong - it gives X = [0, 5, 4, 3, 2, 1] instead X = [1, 2, 3, 4, 5].
I ignored this problem for while and tried this to finish main task:
count(_, [], 0).
count(Num, [H|T], X) :- dif(Num,H), count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1, X<3, X is Num.
res(A, X) :- findall(X,count(_,A,X),X).
But gives strange result: X = [0, 1]
Where i'm wrong? Thank you.
Reusing your first count predicate,
%countElement(Element, List, Nb_Element_in_List)
countElement(_, [], 0).
countElement(Num, [H|T], X) :- dif(Num,H), countElement(Num, T, X).
countElement(Num, [H|T], X) :- Num = H, countElement(Num, T, X1), X is X1 + 1.
Here is the predicate query/1
query(X) :-
L = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5],
countOneByOne(L, L, [], X).
%countOneByOne(A1,A2,In,Out)
%For each Element of A1, if it satisfies countElement(Element,A2,N) & N>4, is accumulated with In, to give Out
%Out is the list of Elements of A1 that satisfies countElement(Element,A2,N) & N>4, added to In
countOneByOne([], _, X, X).
countOneByOne([H|Xs], L, X1, X2) :-
countElement(H, L, N), N<4, !,
countOneByOne(Xs, L, X1, X2).
countOneByOne([H|Xs], L, X1, X2) :-
removeElement(Xs, H, Ss),
countOneByOne(Ss, L, [H|X1], X2).
%remove(List, Element, List_Without_Element)
removeElement( [], _, []).
removeElement([X|Xs], H, [X|R1]) :-
dif(X,H), removeElement(Xs, H, R1).
removeElement([X|Xs], X, R1) :-
removeElement(Xs, X, R1).
Not an answer but another approach using foldl/4 and the dict of SWI-Prolog.
Whenever I hear "scan through a list to perform a computation with a final result at the end", the appropriate approach is probably the "accumulator idiom". One hands a data structure (the "accumulator") between the calls where something happens with a list element, "accumulating" the result. foldl/N is meant to provide boilerplate code around this.
In this case the accumulator is the SWI_prolog dict accumulating "occurrence counts", which happens at each call to inc_for_key/3. At the end, we just need to select the entries with a high enough occurence count:
filter_occurrences(List,Limit,Reacheds,Finals) :-
foldl(inc_for_key,List,_{},Finals),
findall(Key,(Finals.Key >= Limit),Reacheds).
inc_for_key(Key,DictIn,DictOut) :-
(get_dict(Key,DictIn,X) -> succ(X,XP) ; XP=1),
put_dict(Key,DictIn,XP,DictOut).
Testing using plunit
:- begin_tests(filter_occurrences_less_than_n).
test("filter empty list",true(R == [])) :-
filter_occurrences([],3,R,_).
test("filter nonempty list #1 (limit 3)",true([R,Finals] == [[a,c],foo{a:4,b:2,c:3,d:1,e:1,f:1}])) :-
filter_occurrences([a,b,c,d,c,e,b,a,a,f,a,c],3,R,Finals),
dict_pairs(Finals,foo,_). % Sets the tag of the Finals dict to "foo"
test("filter nonempty list #2 (limit 4)",true([R,Finals] == [[a],foo{a:4,b:2,c:3,d:1,e:1,f:1}])) :-
filter_occurrences([a,b,c,d,c,e,b,a,a,f,a,c],4,R,Finals),
dict_pairs(Finals,foo,_). % Sets the tag of the Finals dict to "foo"
test("filter nonempty list #3 (limit 5)",true([R,Finals] == [[],foo{a:4,b:2,c:3,d:1,e:1,f:1}])) :-
filter_occurrences([a,b,c,d,c,e,b,a,a,f,a,c],5,R,Finals),
dict_pairs(Finals,foo,_). % Sets the tag of the Finals dict to "foo"
:- end_tests(filter_occurrences_less_than_n).
And so:
?- run_tests.
% PL-Unit: filter_occurrences_less_than_n .... done
% All 4 tests passed
true.

implementation of copy in prolog

Given a list of regs regs (1,2,3, ...) what I want the code to do is to copy the position X to X + 1, I put some examples below. I have the following code in prolog:
exe(EA, copy(X), ES):-
EA =.. [reg|TH],
LL1 is X+1,
length(TH,LL),
LL2 is LL+X+1,
length(L1,LL1),
length(L2,LL2),
append(L1,LI1,TH),[EX|L2]=LT1,
flatten(reg[L1,EX,L2], LR),
ES=.. LR.
what i want to show me as a result is:
?- exe(reg(1,2,3,4), copy(2), ES).
result:
?- ES=reg(1,2,2,4)
?- exe(reg(4,6,2,9), copy(1), ES).
result:
?-ES=reg(4,4,2,9).
?- exe(reg(1,2), copy(2), ES).
result:
false
I think the code is wrong
Try to split up your goal into multiple aspects, like: getting the element at position X (nth_element), then try to implement a predicate overwriting a particular value. Below is code that works as you expect. It basically traverses lists in the Prolog-"standard" way.
% Get the nth element of a list, indices starting at 1
nth_element([X|_], 1, X) :- !.
nth_element([_|Xs], N, R) :-
M is N - 1,
nth_element(Xs, M, R).
% Overwrites the N-th position in a list by a new element
% Indices starting with 1
% overwrite(List, N, Element, New_List) :-
% overwrite([], _, _, []) :- !.
overwrite([_|Xs], 1, Y, [Y|Xs]) :- !.
overwrite([X|Xs], N, Y, [X|Ys]) :-
M is N - 1,
overwrite(Xs, M, Y, Ys).
exe(EA, copy(X), Es):-
EA =.. [reg|TH],
nth_element(TH, X, Element),
Y is X + 1,
overwrite(TH, Y, Element, New),
Es =.. [reg|New].

Lists size multiplication

I'm new to Prolog and I'm trying to get my head around lists. The problem I'm struggling with is:
Given numbers in the form of lists (1 : [x], 3: [x, x, x]), implement the 'times' predicate /3.
E.g.: times([x, x], [x, x, x], R).
R = [x, x, x, x, x, x].
The plus, and successor predicates where 2 previous points of the exercise. I know I'm not using the successor predicate, but it didn't seem that useful later on.
This is what i've tried so far
successor([], [x]).
successor([X|T], R) :-
append([X|T], [X], R).
plus(L1, L2, R) :- append(L1, L2, R).
times([], _, []).
times(_, [], []).
times([_], L, L).
times(L, [_], L).
times([_|T], L2, R) :- plus(L2, R, RN),
times(T, L2, RN).
The output is:
R is [].
I think you make things too complicated here. You can define successor as:
successor(T, [x|T]).
We can define plus/3 as:
plus([], T, T).
plus([x|R], S, [x|T]) :-
plus(R, S, T).
This is more or less the implementation of append/3, except that here we check if the first list only contains x.
For times/3 we know that if the first item is empty, the result is empty:
times([], _, []).
and for a times/3 where the first item has shape [x|R], we need to add the second item to the result of a call to times/3 with R:
times([x|R], S, T) :-
times(R, S, T1),
plus(S, T1, T).
So putting it all together, we obtain:
successor(T, [x|T]).
plus([], T, T).
plus([x|R], S, [x|T]) :-
plus(R, S, T).
times([], _, []).
times([x|R], S, T) :-
times(R, S, T1),
plus(S, T1, T).

List in certain range

I have a predicate that is supposed to form a list from list, taking into a new list only these numbers that are in a certain range. The predicate works, but suppose that I want to get a list not including bounds.
So I change the condition A >= L, A =< R to A > L, A < R, but then I only get "True", and Prolog outputs nothing.
What could be a problem here?
My code is:
range([], _, _, []).
range([A|L1], L, R, [A|L2]) :-
A>L,
A<R,
range(L1, L, R, L2).
range([A|L1], L, R, L2) :-
A=<L;
A>=R,
range(L1, L, R, L2).
This is what program outputs:
range([1,2,3,4,5], 1,4, X).
?- range([1,2,3,4,5,6,7,8,9,10], 1,3, X).
true .
This is what I want it to output:
?- range([1,2,3,4,5,6,7,8], 1, 5, X).
X = [2,3,4] .
I think you forgot needed parenthesis
range([A|L1], L, R, L2) :-
( A=<L ; A>=R ),
range(L1, L, R, L2).
otherwise, when A=<L, you loose the recursive call, and then variables remain not instantiated.
Priority of the conjunction and disjuntion, , and ;, makes it necessary to write the third clause as:
range([A|L1], L, R, L2) :-
( A=<L
; A>=R
),
range(L1, L, R, L2).

Resources