Related
This recursion should slice IL to IR out of the list Lin and hand result LOut...
slice(_,IL,IR,LOut) :-
IR<IL,
[LOut].
slice(Lin,IL,IR,LOut) :-
nth0(IL,Lin,X),
append(LOut,[X],LOut2),
IK is IL + 1,
slice(Lin,IK,IR,LOut2).
Input / Output:
?- slice([1,2,3,4],2,3,X).
ERROR: source_sink `'3'' does not exist
ERROR: source_sink `'4'' does not exist
X = [] .
I m also new to Prolog, but I think this recursion must somehow work. Also I'm not really known to the error codes in Prolog, but after checking multiple times I just have to give up... I hope you guys can help me.
slice(_,IL,IR,LOut) :-
IR<IL,
[LOut]. % <-- this line causes source_sink error.
That syntax [name] tries to load the file name.pl as Prolog source code. By the time your code gets there, LOut is [3,4] so it tries to load the files 3.pl and 4.pl, and they don't exist (thankfully, or else who knows what they could do).
I think this recursion must somehow work
It won't; you are appending to a list as you go down into the recursion, which means you will never see the result.
The following might be a close version which works, at least one way:
slice(_,IL,IR,[]) :-
IR < IL.
slice(Lin,IL,IR,[X|LOut]) :-
IR >= IL,
nth0(IL,Lin,X),
IK is IL + 1,
slice(Lin,IK,IR,LOut).
?- slice([0,1,2,3,4,5,6,7,8,9], 2, 5, X).
X = [2, 3, 4, 5]
See how [X|LOut] in the second rule's header puts X in the result that you get, and append/3 is not needed, and LOut finishes down in the recursion eventually as [] the empty list from the first rule, and all the X's are prepended on the front of it to make the result on the way down into the recursion, which is tail recursion, so it doesn't need to go back up, only forward, since there's nothing left to be done after the recursive call.
Since the "cons" is done before the recursion, this is known as "tail recursion modulo cons" in other languages, but in Prolog it is just tail, and the list is being built top-down on the way forward, as opposed to being built bottom up on the way back:
Lin=[0,1,2,3,4,5,6,7,8,9], slice( Lin, 2, 5, R)
:-
nth0(2,Lin,X2), R=[X2|R2], slice( Lin, 3, 5, R2)
:-
nth0(3,Lin,X3), R2=[X3|R3], slice( Lin, 4, 5, R3)
:-
nth0(4,Lin,X4), R3=[X4|R4], slice( Lin, 5, 5, R4)
:-
nth0(5,Lin,X5), R4=[X5|R5], slice( Lin, 6, 5, R5)
:-
R5 = [].
I think findall/3 provides a readable readable solution for your problem:
slice(Lin,IL,IR,LOut) :-
findall(E,(nth0(P,Lin,E),between(IL,IR,P)),LOut).
yields
?- slice([1,2,3,4],2,3,X).
X = [3, 4].
If you expect a different outcome, use standard arithmetic comparison operators (=<,>=) instead of between/3.
I think you want:
list_elems_slice(Start, End, Lst, Slice) :-
list_elems_slice_(Lst, 1, Start, End, Slice).
list_elems_slice_([H|T], N, N, End, [H|Slice]) :-
list_elems_slice_capture_(T, N, End, Slice).
list_elems_slice_([_|T], N, Start, End, Slice) :-
N1 is N + 1,
list_elems_slice_(T, N1, Start, End, Slice).
list_elems_slice_capture_(_, N, N, []).
list_elems_slice_capture_([H|T], N, End, [H|Slice]) :-
N1 is N + 1,
list_elems_slice_capture_(T, N1, End, Slice).
Result in swi-prolog:
?- list_elems_slice(S, E, [a,b,c], Slice).
S = E, E = 1,
Slice = [a] ;
S = 1,
E = 2,
Slice = [a, b] ;
S = 1,
E = 3,
Slice = [a, b, c] ;
S = E, E = 2,
Slice = [b] ;
S = 2,
E = 3,
Slice = [b, c] ;
S = E, E = 3,
Slice = [c] ;
false.
Assuming that the point of this exercise is to teach you to think recursively, I would approach the problem as follows.
To get what you want is essentially two separate operations:
You first must discard some number of items from the beginning of the list, and then
Take some number of items from what's left over
That gives us discard/3:
discard( Xs , 0 , Xs ) .
discard( [_|Xs] , N , Ys ) :- N > 0 , N1 is N-1, discard(Xs,N1,Ys) .
and take/3, very nearly the same operation:
take( _ , 0 , [] ) .
take( [X|Xs] , N , [Y|Ys] ) :- N > 0 , N1 is N-1, take(Xs,N1,Ys) .
Once you have those two simple predicates, slice/4 itself is pretty trivial:
%
% slice( List , Left, Right, Sublist )
%
slice( Xs, L, R, Ys ) :- % to slice a list,
L =< R, % - the left offset must first be less than or equal to the right offset
N is R-L, % - compute the number of items required, and then
discard(Xs,L,X1), % - discard the first L items, and
take(X1,N,Ys). % - take the next N items
. % Easy!
Another approach would be to use append/3:
slice( Xs , L, R, Ys ) :-
length(Pfx,L), % - construct of list of the length to be discarded
append(Pfx,Sfx,Xs), % - use append to split Xs
N is R-L, % - compute the number of items required
length(Ys,N), % - ensure Ys is the required length
append(Ys,_,Sfx) % - use append to split off Ys
. % Easy!
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
I need to multiply and sum one list, the output should be like this:
?- tp4([1,7,0,1,2,3,5], L).
L = [210,19,1,7,0,1,2,3,5]
First the multi, next the sum and at the end the rest of the numbers.
Here is a builing brick answer to your question since you seem to have a "where to start" problem. It is important to learn it by yourself, therefore you can conclude the correct answer by using maplist/2 and fold/4 as mentioned from David Tonhofer. But these are "advanced" predicates, so lets start from scratch and implement the base functionalities.
First: how to append elements to a list. You can either put something as a head of a list ([Head|List]) or use the predicate append/2 (which is build in but you can easily implement it by yourself). Note that variables start with a capital letter.
?- List=[1,2,3,4], Head = 0, Out=[Head|List].
Head = 0,
List = [1, 2, 3, 4],
Out = [0, 1, 2, 3, 4].
?- List2=[1,2,3,4], List1 = [0], append(List1,List2,Out).
List1 = [0],
List2 = [1, 2, 3, 4],
Out = [0, 1, 2, 3, 4].
You are be able to add elements to a list.
If you want to implement your own predicate, which works on lists, you either use the inbuild predicates or implement it yourself. We'll do the second one for the example of subtraction (all elements are subtracted from the last element).
Our predicate subtract/2 needs 2 attributes: a list (input) and a "return" value (output).
If the list has only one element ([H]), return the element. Otherwise split the list into a Head element and a Rest list ([Head|Rest]), compute the substract value for the list Rest (Tmp) and subtract Head from it:
subtract([H],[H]).
subtract([Head|Rest], Sub):-
subtract(Rest,Tmp),
Sub is Tmp - Head.
Test:
?- subtract([1,2,3,10],O).
O = 4 ;
false.
Works, not perfect but works. Now you know how to add elements to a list and have an example how to build predicated which operate on lists and use arithemtic functions. Now you can build your desired function.
You need to walk the list and compute the product and sum as you go from element to element. Given the neutral elements of the product and sum are, respectively, 1 and 0:
product_sum_list([Head| Tail], [Product, Sum, Head| Tail]) :-
product_sum_list(Tail, Head, 1, Product, 0, Sum).
Note that we're requiring the list to have at least one element. The auxiliary product_sum_list/6 performs the actual computation of the product and sum:
product_sum_list([], Last, Product0, Product, Sum0, Sum) :-
Product is Product0 * Last,
Sum is Sum0 + Last.
product_sum_list([Next| Tail], Current, Product0, Product, Sum0, Sum) :-
Product1 is Product0 * Current,
Sum1 is Sum0 + Current,
product_sum_list(Tail, Next, Product1, Product, Sum1, Sum).
By splitting the list between its head tail moving the tail to the first argument of the auxiliary predicate, we take advantage of the first argument indexing provided by the generality of Prolog systems to avoid the creation of spurious choice-points.
Sample call:
| ?- product_sum_list([1,7,0,1,2,3,5], L).
L = [0,19,1,7,0,1,2,3,5]
yes
You can achieve the same results using, as David suggested, meta-predicates for mapping and folding lists. But given that we need to compute both product and sum, the straight-forward solution is simpler and more efficient.
A common Prolog idiom is the use of a helper predicate, that takes extra arguments that maintain state. These also help you get to tail recursion so as to not consume stack.
The naive way to multiply a list might be:
multiply( [] , 0 ) . % The empty list has a product of zero.
multiply( [P] , P ) . % A list of length 1 is the value of the singleton element.
multiply( [N|Ns] , P ) :- % To compute the product of a list of length > 1...
multiply(Ns,T), % - recursively multiply the tail of the list, then
P is N * T % - multiply the head by the product of the tail
. % Easy!
Summation would be pretty much identical save for the operation involved.
[Note: given a list of sufficient length, this would eventually fail due to a stack overflow.]
Using a helper predicate (1) makes it tail recursive, meaning it won't blow up and die on a long list, and (2) will facilitate combining summation and multiplication. The 'helper' implementation looks like this:
multiply( [] , 0 ) .
multiply( [N|Ns] , P ) :- multiply(Ns,N,P).
multiply( [] , P , P ) .
multiply( [N|Ns] , T , P ) :-
T1 is T * N ,
multiply( Ns, T1, P )
.
And summation, again, is pretty much identical.
Now we can combine them to get what you want:
multiply_and_sum( [] , [0,0] ) .
multiply_and_sum( [N|Ns] , [P,S|Ns] ) :-
multiply_and_sum( Ns, N, N, P, S )
.
multiply_and_sum( [] , P, S, P, S ) .
multiply_and_sum( [N|Ns] , X, Y, P, S ) :-
X1 is X * N,
Y1 is Y + N,
multiply_and_sum( Ns, X1, Y1, P , S )
.
i would like to create a list in prolog where in each recursive step i add an element to the list.My code:
solve(N,List):-
N>5,
solve(N-1,[a|List]),
N<5,
solve(N-1,[b|List]),
N is 0.
This supposedly runs recursions adding a or b to the List depending on N.However this [a|List] does not add an element in each recursion.What is the correct way to do this?
You basically need to write three clauses. First, the clause for N = 0.
solve(0, []).
When N is less than (or equal to) 5, you want to add b to the list. You also need to check that N is not negative, otherwise your program will recurse at infinity. You also need to calculate N - 1 with the is predicate.
solve(N, [b | L]) :-
N >= 0,
N =< 5,
M is N - 1,
solve(M, L).
The third clause is for the case where N is greater than 5, where a is added to the list.
solve(N, [a | L]) :-
N > 5,
M is N - 1,
solve(M, L).
Querying for solve(2, L) and solve(7, L) yields respectively:
L = [b, b] % N = 2
L = [a, a, b, b, b, b, b] % N = 7
I assume you are trying to do this:
solve(0, []).
solve(N, [a|List]):-
N > 5,
solve(N-1,List).
solve(N, [b|List]):-
N =< 5,
solve(N-1,List).
i am a begginer in prolog and i want to write a code that creates a list based on another list.I wrote this :
create([_],N,J,K,J):- N>K.
create([X|Xs],N,L,K,J):- X==N , N1 is N + 1 , create(Xs,N1,[-1|L],K,J).
create([X|Xs],N,L,K,J):-N1 is N + 1 , create([X|Xs],N1,[0|L],K,J).
K is the size of the output list.
N is a counter .
L is the output.
X is the input list.
?- create([1,2],1,[],5,N).
N = [0, 0, 0, 0, -1]
i would like to get a list with size equal to 5(K) filled with zeros except the positions that are specified in the input list on which the value will be -1(I didnt reverse it).
I think your code should be - note the list is built in the head, to avoid reversing)
create(_ ,N,K, []) :- N > K, !.
create([N|Xs],N,K,[-1|L]) :- !, N1 is N + 1, create(Xs,N1,K,L).
create( Xs ,N,K,[ 0|L]) :- N1 is N + 1, create(Xs,N1,K,L).
It requires the zeros positions sorted.
Otherwise, the more idiomatic - and cryptic -
create(Ps, N,K, L) :- findall(D, (
between(N,K,P),
( memberchk(P,Ps) -> D = -1 ; D = 0)), L).
will work regardless the ordering.