This is a problem suma( [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 5 ], [ 3, 4, 5, 6 ] ], X ), and i need to get this result X = [ 10, 14, 18 ]. I don't have any idea how to figure this out. Please help
maplist/3 and foldl/4 and yall notation (the last one available in SWI-Prolog) are your friends.
suma(ListOfLists,ListOfSums) :-
maplist(
([Sublist,Sum]>>
(foldl(
[AccumIn,X,AccOut]>>(AccOut is AccumIn + X),
Sublist,
0,
Sum))),
ListOfLists,
ListOfSums).
Thus:
?- suma( [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 5 ], [ 3, 4, 5, 6 ] ], X ).
X = [10, 14, 18].
This is less logic programming than functional programming, but if one has a Swiss Army Knife, one might as well use it!
maplist/3: Calls the goal that is on argument position 0 for every pair [Sublist,Sum] where Sublist is an element of the list on argument position 1 (i.e. ListOfLists) and Sum is an element of the list on argument position 2 (i.e. ListOfSums), both elements being at the same position in their respective lists.
The goal called takes [Sublist,Sum] and calls foldl/4, which "folds-left" the list Sublist using the goal on argument position 0, starting with value 0 and resulting in value Sum.
The folding operation is simply arithmetic addition via [AccumIn,X,AccOut]>>(AccOut is AccumIn + X).
This can be more extensively written as:
suma(ListOfLists,ListOfSums) :-
maplist(
p2, % will be called with 2 parameters
ListOfLists,
ListOfSums).
p2(Sublist,Sum) :-
foldl(
p3, % will be called with 3 parameters
Sublist,
0,
Sum).
p3(AccumIn,X,AccOut) :-
AccOut is AccumIn + X.
We can run some plunit test cases for good measure (actually, the problem to solve should be stated with the below, TDD and all that):
:- begin_tests(sum_over_sublists).
test("empty list of lists",true(R == [])) :-
suma([],R).
test("all sublists contain one value",true(R == [1,2,3])) :-
suma([[1],[2],[3]],R).
test("one sublist is empty",true(R == [1,0,3])) :-
suma([[1],[],[3]],R).
test("standard case #1",true(R == [6,15,24])) :-
suma([[1,2,3],[4,5,6],[7,8,9]],R).
test("standard case #2",true(R == [10,14,18])) :-
suma([[1,2,3,4],[2,3,4,5],[3,4,5,6]],R).
:- end_tests(sum_over_sublists).
And so:
?- run_tests.
% PL-Unit: sum_over_sublists ..... done
% All 5 tests passed
true.
%! sum(Xs,SUM)
%
% calculate the total sum of the items in list `Xs` .
sum(Xs,SUM)
:-
sum(Xs,0,SUM)
.
sum([],SUM0,SUM0) .
sum([X0|Xs],SUM0,SUM)
:-
SUM1 is SUM0 + X0 ,
sum(Xs,SUM1,SUM)
.
/*
?- sum([1,2,3,4],SUM).
SUM = 10.
?- sum([2,3,4,5],SUM).
SUM = 14.
?- sum([3,4,5,6],SUM).
SUM = 18.
*/
%! suma(Xss0,SUM)
%
% calculate the total sum of the items in list of lists `Xss` .
suma([],0) .
suma([Xs0|Xss0],SUM)
:-
sum(Xs0,SUM0) ,
suma(Xss0,SUM1) ,
SUM is SUM0 + SUM1
.
/*
?- suma([[1,2,3,4],[2,3,4,5]],SUM).
SUM = 24.
?- suma([[1,2,3,4],[2,3,4,5],[3,4,5,6]],SUM).
SUM = 42.
*/
Related
Given a list of positive integer Items whose elements are guaranteed to be in sorted ascending order, and a positive integer Goal, and Output is a list of three elements [A,B,C] taken from items that together add up to goal. The Output must occur inside the items list in that order (ascending order).
ex:
?- threeSum([3,8,9,10,12,14],27,Output).
Output=[8,9,10];
Output=[3,10,14].
someone helped me to reach this to this code
but it gives me singleton variables:[Input,Items] ,it didnt work
although iam not quite sure if this is a greedy algorithm search or not ?
threeSum(Input,Goal,[A,B,C]):-
permutation(Items, [A,B,C|Rest]),
msort([A,B,C],[A,B,C]),
msort(Rest,Rest),
sum_list([A,B,C],Goal).
A clpfd approach:
:- use_module(library(clpfd)).
threeSum(Input, Goal, [A,B,C]) :-
Input = [First|Rest],
foldl([N,M,T]>>(T = N\/M), Rest, First, Domain),
[A,B,C] ins Domain,
all_different([A,B,C]),
chain([A,B,C], #>=),
Goal #= A + B + C,
labeling([max(A), max(B), max(C)], [A,B,C]).
Which has a bit of wrangling to turn the list of numbers into a domain, then says [A,B,C] must be in the list of numbers, must be different numbers, must be in descending order, must sum to the goal, and the clpfd solver should strive to maximise the values of A then B then C. (This probably won't work if the list can contain multiple of the same value like [5,5,5,3,2]).
e.g.
?- threeSum([3,8,9,10,12,14], 27, Output).
Output = [14, 10, 3] ;
Output = [10, 9, 8]
nums_goal_answer(Input, Goal, [A,B,C]) :-
length(Input, InputLen),
reverse(Input, RInput), % 'greedy' interpreted as 'prefer larger values first'.
% and larger values are at the end.
between( 1, InputLen, N1),
between(N1, InputLen, N2), % three nested for-loops equivalent.
between(N2, InputLen, N3),
\+ N1 = N2, % can't pick the same thing more than once.
\+ N2 = N3,
nth1(N1, RInput, A, _),
nth1(N2, RInput, B, _),
nth1(N3, RInput, C, _),
sum_list([A,B,C], Goal).
someone helped me to reach this to this code but it gives me singleton variables:[Input,Items], it didnt work
The warning is because the code never looks at the numbers in the Input list. Without doing that, how could it ever work?
although iam not quite sure if this is a greedy algorithm
is it taking the biggest things first? I don't think permutation will do that.
Using DCG:
:- use_module(library(dcg/basics)).
three_sum_as_dcg(Total, Lst, LstThree) :-
phrase(three_sum_dcg(3, Total), Lst, LstThree).
% When finished, remove the remainder, rather than add to LstThree
three_sum_dcg(0, 0) --> remainder(_).
three_sum_dcg(NumsLeft, Total), [N] -->
% Use this element
[N],
{ three_sum_informed_search(NumsLeft, Total, N),
succ(NumsLeft0, NumsLeft),
Total0 is Total - N
},
three_sum_dcg(NumsLeft0, Total0).
three_sum_dcg(NumsLeft, Total) -->
% Skip this element
[N],
{ three_sum_informed_search(NumsLeft, Total, N) },
three_sum_dcg(NumsLeft, Total).
three_sum_informed_search(NumsLeft, Total, N) :-
NumsLeft > 0,
% "Informed" search calc due to list nums not decreasing
Total >= (N * NumsLeft).
Result in swi-prolog (note the efficiency):
?- numlist(1, 1000000, L), time(findall(L3, three_sum_as_dcg(12, L, L3), L3s)).
% 546 inferences, 0.000 CPU in 0.000 seconds (97% CPU, 4740036 Lips)
L3s = [[1,2,9],[1,3,8],[1,4,7],[1,5,6],[2,3,7],[2,4,6],[3,4,5]].
Restating the problem statement:
Given that I have
A [source] list of positive integers, whose elements are guaranteed to be sorted in ascending order, and
a positive integer indicating the target value.
I want to find
an ordered subset of elements of the source list that sum to the target value
The simplest way is often the easiest (and the most general):
sum_of( _ , 0 , [] ) . % nothing adds up to nothing.
sum_of( [X|Xs] , S , [X|Ys] ) :- % otherwise...
S > 0 , % - if the target sum S is positive,
X =< S , % - and the head of the list is less than or equal to the target sum
S1 is S-X , % - remove that amount from the target sum, and
sum_of(Xs,S1,Ys) . % - recurse down with the new target sum
sum_of( [_|Xs] , S , Ys ) :- % then, on backtracking...
S > 0 , % - assuming that the target sum is positive,
sum_of(Xs,S,Ys). % - recurse down again, discarding the head of the list
This will find whatever combinations of however many list elements sum to the target value. It will find them from left to right, so
sum_of( [1,2,3,4,5,6,7,8,9], 10, L ).
will, on backtracking successively find
L = [ 1, 2, 3, 4 ]
L = [ 1, 2, 7 ]
L = [ 1, 3, 6 ]
L = [ 1, 4, 5 ]
L = [ 1, 9 ]
L = [ 2, 3, 5 ]
L = [ 2, 8 ]
L = [ 3, 7 ]
L = [ 4, 6 ]
If you want to change the order so it finds the largest values first, simply reverse the order of clauses 2 and 3 in sum_of/3:
sum_of( _ , 0 , [] ) .
sum_of( [_|Xs] , S , Ys ) :-
S > 0 ,
sum_of(Xs,S,Ys) .
sum_of( [X|Xs] , S , [X|Ys] ) :-
S > 0 ,
X =< S ,
S1 is S-X ,
sum_of(Xs,S1,Ys) .
Now it will return the same set of solutions, just in the reverse order, starting with [4,6] and finishing with [1,2,3,4].
Once you have solved the general problem, it's a simple matter of restricting it to a specified number of elements, for instance:
sum_of_n_elements(Xs,N,S,Ys) :- length(Ys,N), sum_of(Xs,S,Ys).
And to get just the 3-element subsets that sum to the target value:
sum_of_3_elements(Xs,S,Ys) :- sum_of_n_elements(Xs,3,S,Ys) .
https://swish.swi-prolog.org/p/XKjdstla.pl
Here is my exercise: define a predicate in prolog which, applied to a list L of integers, gives as a result the list of the successors of the even elements present in L.
The code i wrote work only if one element is even , can someone help me figure out where I'm wrong?
even(X):- 0 is mod(X,2).
odd(X):- 1 is mod(X,2).
list_even([],[]).
list_even([T|C],K):- even(T), E is T+1, list_even(C,K1), append(K1,E,X), K is X.
list_even([T|C],K):- odd(T),list_even(C,K).
Some flaws in your code are:
append(K1, E, X): This goal should append two lists to generate a third list; however, E is just an element, not a list. So you need to write append(K1, [E], X).
K is X: This goal evaluates the arithmetic expression represented by the variable X and unifies its value with variable K; however, X is a list, not an arithmetic expression. So you need to remove it.
So the correct code would be as follows:
list_even([], []).
list_even([T|C], K):- even(T), E is T+1, list_even(C, K1), append(K1, [E], K).
list_even([T|C], K):- odd(T), list_even(C, K).
Example:
?- list_even([1, 20, 3, 40, 5, 7, 8], Successors).
Successors = [9, 41, 21] ;
false.
Note that in the obtained answer, the successors appear in reverse order (the first even element in the input list is 20, but its successor 21 is the last element in the output list).
So a better code is as follows:
even_number_successors([], []).
even_number_successors([X|Xs], Successors) :-
( X mod 2 =:= 0
-> Y is X + 1,
Successors = [Y|Ys]
; Successors = Ys ),
even_number_successors(Xs, Ys).
Example:
?- even_number_successors([1, 20, 3, 40, 5, 7, 8], Successors).
Successors = [21, 41, 9].
From your problem statement,
define a predicate in prolog which, applied to a list L of integers, gives as a result the list of the successors of the even elements present in L.
On the face of things, you don't need odd/1: that which is not even is odd.
Why use append/3? You're just iterating/filtering a list and constructing a new one, right? Instead, you can construct the list in order by leaving the list incomplete, with an unbound tail. As we recurse down, we build out the tail of the list, either by unifying it with a new list, or at the end, unifying it with the empty list, the atom []).
I would do something like this:
list_even( [] , [] ) . % empty list? All done.
list_even( [X|Xs] , [Y|Ys] ) :- % non-empty?
even(X), % - is X even? if so...
!, % - eliminate the choice point
Y is X+1, % - get the successor of X
list_even(Xs,Ys) % - recurse down
. %
list_even( [_|Xs] , Ys ) :- % Otherwise, the head of the list is odd: discard the head, and...
list_even(Xs,Ys) % - recurse down
. % Easy!
even(X) :- 0 =:= X .
I am a beginner in Prolog, and I've searched a lot but cannot solve the problem. The question is giving me a list given the head of the list, such as [20,_,_,_].
The length of the list is unknown. For example, it could be [30,_,_,_,_,_].
the _ is the distinct factor, which only consists of the digit from 1 to 9. For example, [20,_,_,_] could generate [1,4,5] and its combination.
The list could be filled with a number first. For example, [20,_,4,_]. The output would be still [1,4,5] and [5,4,1].
What I've tried is to rip off the head of the list, and try to generate the rest of the elements back to the original list, but I failed, and cannot understand the debugger and its trace information.
removeHead([Head|Tail],Tail).
get_head_element([],_).
get_head_element([Head|Rest],Head).
divide(1,[],_).
divide(Number,[Head|List],Result):-
0 is mod(Number,Head),
Quotient is Number/Head,
divide(Quotient,List,Result).
solve_multiply(Row,RestRow):-
get_head_element(Row, Goal),
removeHead(Row,RestRow),
all_distinct(RestRow),
RestRow ins 1..9,
divide(Goal,RestRow,RestRow).
Any hint of resource that I can keep approaching this question? Thanks.
EDIT:
I think it another way that the elements multiplied in the list would be the same at the head, so I wrote a multiply predicate.
%% multiply(+List,-Result)
%
% for calling the multiply(+List,+PrevResult,+Result) with accumulator set to 1
multiply(List,Result):-
multiply(List,1,Result).
%% multiply(+List,+PrevResult,+Result)
%
% multiply each element in the list
multiply([Element|RestList],PrevResult,Result):-
NextResult is PrevResult * Element,
multiply(RestList,NextResult, Result).
%% multiply([], -Result, -Result).
%
% multiply predicate stops when all the elements have been multiplied
multiply([], Result, Result).
%% solve_multiply(+Row,-RestRow)
solve_multiply(Row,RestRow):-
get_head_element(Row, Goal),
removeHead(Row,RestRow),
RestRow ins 1..9,
multiply(RestRow,Goal), % get the Arguments not sufficiently instantiated message
all_distinct(RestRow).
The simplest way to find the solution is to:
Compare the multiplied elements to the head element.
Use the constraint provided by clpfd.
Therefore, the code should be:
multiply(List,Result):-
multiply(List,1,Result).
multiply([Element|RestList],PrevResult,Result):-
NextResult #= PrevResult * Element, % constraint that works for both side ?X #= ?Y
multiply(RestList,NextResult, Result). % tail recursion
multiply([], Result, Result).
solve_multiply(Row,RestRow):-
get_head_element(Row, Goal),
removeHead(Row,RestRow),
RestRow ins 1..9,
multiply(RestRow,Goal),
all_distinct(RestRow).
When calling the solve_multiply([20,_,_,_],X), labeling([],X). The result is:
X = [1, 4, 5] ;
X = [1, 5, 4] ;
X = [4, 1, 5] ;
X = [4, 5, 1] ;
X = [5, 1, 4] ;
X = [5, 4, 1] ;
false.
When calling the solve_multiply([20,_,1,_],X), labeling([],X). The result is:
X = [4, 1, 5] ;
X = [5, 1, 4].
I want to compare 2 values X and C1 as you can see in code, X is reversed value of C if both values are equal then it should print the compared value please tell me how to do this. It is to print Palindrome Numbers like... 1,11,22,33,44,55,66,77,88,99,101....
go(N):-
write(0),nl,
go(0,N).
go(_,0):- !.
go(A,C):-
A1 is A,
C1 is A1 + 1,
/* write(C1),nl,*/
rev(C1,X),
/* write(X),nl,*/
/* To compare the Value of X and C1 and print if compared value is true*/
NewC is C-1,
go(C1,NewC).
rev(Q,E):-
name(Q, Q1),
reverse(Q1,E1),
name(E,E1).
Describing palindrome numbers is actually a nice task for CLP(FD) and DCGs. First let's describe what the digits of a palindrome number look like:
:- use_module(library(clpfd)).
palindromedigits(Digits) :- % Digits are palindrome digits if
Digits ins 0..9, % they are between 0 and 9
Digits = [H|_], % and the first digit...
H #\= 0, % ... is different from 0
phrase(palindrome, Digits). % and they form a palindrome
palindrome --> % a palindrome is
[]. % an empty list
palindrome --> % or
[_]. % a list with a single element
palindrome --> % or
[A], % an element A
palindrome, % followed by a palindrome
[A]. % followed by an element A
To test if a number is a palindrome, you could turn it into a list of digits and palindromedigits/1 has to hold for that list. To generate such numbers, you could use length/2 to describe lists of all possible lengths, palindromedigits/1 again has to hold for those lists and the digits have to be multiplied by their respective powers of ten and summed up. Since leading zeros are excluded by palindromedigits/1, you'd have to add a fact for 0, if you want to include it in the palindrome numbers. That might look something like this:
palindromenumber(0). % 0 is a palindromenumber
palindromenumber(PN) :- % rule for testing numbers
number(PN), % succeeds if PN is a number
number_codes(PN,C), % C is a list of codes corresponding to the digits
maplist(plus(48),Digits,C), % codes and digits are off by 48
palindromedigits(Digits). % Digits is a palindrome
palindromenumber(PN) :- % rule for generating numbers
var(PN), % succeeds if PN is a variable
length(Digits,_), % Digits is a list of length 0,1,2,...
palindromedigits(Digits), % Digits is a palindrome
digits_number_(Digits,PN,1,0), % Digits correspond to the number PN
label(Digits). % labels the list Digits with actual numbers
Note that the codes corresponding to the digits are off by 48, hence the goal with maplist/3, e.g.:
?- number_codes(123,C), maplist(plus(48),Digits,C).
C = [49, 50, 51], % <- the codes
Digits = [1, 2, 3]. % <- the actual digits
The predicate digits_number_/4 is fairly straight forward. It is called with 1 as the initial power of ten and 0 as the initial accumulator for the number. The digits are multiplied with the power of ten corresponding to their position in the number and subsequently added to the accumulator. If the list of digits is empty, the accumulator holds the number corresponding to the list of digits.
digits_number_([],PN,_,PN).
digits_number_([D|Ds],PN,P,Acc) :-
Acc1 #= Acc + D*B,
P10 #= P*10,
digits_number_(Ds,PN,P10,Acc1).
Note that it doesn't matter that the digits are multiplied with the powers in reverse order, because it's a palindrome number.
Now you can query for palindrome numbers:
?- palindromenumber(PN).
PN = 0 ;
PN = 1 ;
PN = 2 ;
.
.
.
PN = 33 ;
PN = 44 ;
PN = 55 ;
.
.
.
PN = 666 ;
PN = 676 ;
PN = 686 ;
.
.
.
PN = 7667 ;
PN = 7777 ;
PN = 7887
.
.
.
Or you can test if a number is a palindrome:
?- palindromenumber(121).
true ;
false.
?- palindromenumber(123).
false.
?- palindromenumber(12321).
true ;
false.
EDIT
To address the question in your comment, you can do that by describing a relation between such a sequence and it's length. So you'll have a predicate with arity two instead of arity one. Let's give it a nice descriptive name, say firstN_palindromicnumbers/2. The actual realation is described by a predicate with an additional argument that holds the current candidate to be examined. Since you want to start the sequence with 1, that will be the argument firstN_palindromicnumbers_/3 will be called with:
firstN_palindromicnumbers(N,PNs) :-
firstN_palindromicnumbers_(N,PNs,1). % sequence starts with 1
The argument that holds the candidates will be increased by 1 through the recursions, while the first argument, N, will be decreased every time a candidate turns out to be an actual palindromic number. So the predicate eventually ends up with N being 0, an empty list and a candidate we don't care for. That will be the base case. Otherwise the head of the list is the smallest palindromic number in the (remainder of the) sequence. You can reuse the goals number_codes/2 and maplist/3 from above to describe a list of digits corresponding to the current candidate and the DCG palindrome//0 to state that the digits have to be a palindrome. The other goals from the predicate palindromedigits/1 won't be needed, since the candidates will be 1,2,3,..., thus consisting of (at least one) digit(s) from 0 to 9 without leading zeros. You can express this in Prolog like so:
firstN_palindromicnumbers_(0,[],_C). % base case
firstN_palindromicnumbers_(N1,[C0|PNs],C0) :- % case: C0 is a palindrome
N1 #> 0, % sequence is not of desired length yet
number_codes(C0,Codes),
maplist(plus(48),Digits,Codes),
phrase(palindrome, Digits), % digits form a palindrome
N0 #= N1-1, % sequence of length N1-1 has to be described yet
C1 #= C0+1, % C1 is the next candidate
firstN_palindromicnumbers_(N0,PNs,C1). % PNs is the rest of the sequence
firstN_palindromicnumbers_(N1,PNs,C0) :- % case: C0 ain't a palindrome
N1 #> 0, % sequence is not of desired length yet
number_codes(C0,Codes),
maplist(plus(48),Digits,Codes),
\+ phrase(palindrome, Digits), % digits don't form a palindrome
C1 #= C0+1, % C1 is the next candidate
firstN_palindromicnumbers_(N1,PNs,C1). % PNs is the rest of the sequence
Now you can query the predicate for a sequence of palindromic numbers of given length (Note that with SWI-Prolog you might have to hit w to see the entire list):
?- firstN_palindromicnumbers(15,PNs).
PNs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] [write] % <- hit the w key
PNs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66] ;
false.
?- firstN_palindromicnumbers(25,PNs).
PNs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161] ;
false.
You can also use the predicate to check if a given list is the sequence of the first N palindrommic numbers:
?- firstN_palindromicnumbers(N,[1,2,3,4,5]).
N = 5 ;
false.
?- firstN_palindromicnumbers(N,[0|_]).
false.
?- firstN_palindromicnumbers(N,[1,2,3,4,11]).
false.
And the most general query yields the expected answers as well:
?- firstN_palindromicnumbers(N,PNs).
N = 0,
PNs = [] ;
N = 1,
PNs = [1] ;
N = 2,
PNs = [1, 2] ;
N = 3,
PNs = [1, 2, 3] ;
.
.
.
I'm working on a Prolog application that will go through a list of values and copy the values to another list. If a value is a number, then I want to square that number, otherwise, copy the value.
So given the input:
[k, 4, 9, b]
It should yield:
[k, 16, 81, b]
Here is what I have:
squareMe(X, P) :- P is X * X.
boogie([],[]).
% The next line is where I'm having problems
boogie([X|T], [X|Result]):-
number(X),
boogie(T,Result).
boogie([ThrowAway|Tail], [ThrowAway|Result]):-
boogie(Tail,Result).
Right now, this almost works. So the first thing I tried was:
boogie([X|T], [X*X|Result):-
Prolog would not evaluate the expression because you need "is". So I tried:
boogie([X|T], [Y is X*X|Result):-
That didn't work. I tried:
boogie([k, 4, 9, b], T).
My output was:
T = [k, _G3648 is 4*4, _G3657 is 9*9, b].
Is there a way that I can obtain the square of a number within the list?
i.e.
boogie([X|T], [Square of X|Result]):-
What about
boogie([X|T], [Y|Result]):-
number(X),
Y is X*X,
boogie(T,Result).
?
I will admit I haven't done prolog in years, but your approach confuses me a bit. Wouldn't it be easier to simply have a predicate that 'processes' individual tokens, and then use it to recursively process each token in the input list? e.g.
%% In file 'boogie.pl'
% 'processToken' predicate
processToken( Unprocessed, Processed ) :- number( Unprocessed ),
Processed is Unprocessed ^ 2,
!.
processToken( Unprocessed, Processed ) :- not( number( Unprocessed )),
Processed = Unprocessed.
% 'processList' predicate
processList( [], [] ). % Base case
processList( InputList, OutputList ) :- [H_in | T_in ] = InputList,
[H_out | T_out ] = OutputList,
processToken( H_in, H_out ),
processList( T_in, T_out ),
!.
Then at your prolog console:
?- consult( 'boogie.pl' ).
% boogie.pl compiled 0.00 sec, 1 clauses
true.
?- processList( [1, 2, a, v, 'hi there', '5', 6], Out ).
Out = [1, 4, a, v, 'hi there', '5', 36].