creating a list in prolog based on an other list - prolog

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.

Related

Impossible for me to solve: Simple recursion does not take integers for indexing a list....source_sink does not exist?

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!

using greedy algorithm search in lists

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

Creating a List in prolog recursively

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).

Prolog: How do I return multiple values?

I want to take a value, such as 3 and return all from the given value to one. For example, if I passed in count(3), I would get 3,2, 1 separately. I don't want to return the values as a list. For what I wrote I tried to first return a value and then recursively call the next value to return. This however only returns once. What am I doing wrong?
count(0,1).
count(N,F) :-
N1 is N-1,
F is N-1,
count(N1,F1).
count(S0, S) :-
closure0(\X0^X^succ(X,X0), S0, S).
using this definition and lambdas
or
count(N,N).
count(N0,N) :-
succ(N1,N0),
count(N1,N).
or in plain ISO Prolog:
count(N,N).
count(N0,N) :-
N0 > 0, % or 1
N1 is N0-1,
count(N1,N).
May be something like that :
count(N,F) :-
N > 0,
( F = N
; N1 is N-1,
count(N1,F)).
You get
?- count(3,V).
V = 3 ;
V = 2 ;
V = 1 ;
false.

Prolog: Decrementing variable in argument

I am new to Prolog and was tasked with a Fibonnaci predicate fib( N, F) where N is the number in sequence, and F is the value. What I came up with does not work, but the solution I found seems identical to me... I cannot understand the difference.
My version:
/* MY VERSION, DOES NOT WORK */
fib( 0, 0).
fib( 1, 1).
fib(N,F) :-
N > 1,
fib(N-1,F1),
fib(N-2,F2),
plus(F1,F2,F).
The working version:
/* FOUND SOLUTION, DOES WORK */
fib( 0, 0).
fib( 1, 1).
fib(N,F) :-
N > 1,
N1 is N-1,
N2 is N-2,
fib(N1,F1),
fib(N2,F2),
plus(F1,F2,F).
Obviously the problem has something to do with me using "N-1" and "N-2" as arguments rather than assigning those values to new variables first. But I don't get it... because in other recursive Prolog codes, I have successfully done just that (decremented a variable right in the argument slot). Does this make sense?
Thanks!
Below is an example where the "N-1" did work.
line( N, _, _) :-
N =:= 0.
line( N, M, Char) :-
N > 0,
N mod M =\= 1,
write( Char), write( ' '),
line( N-1, M, Char).
line( N, M, Char) :-
N > 0,
N mod M =:= 1,
write( Char), write( '\n'),
line( N-1, M, Char).
square( N, Char) :-
N > 0,
line( N*N, N, Char).
A new version of fib/2 which also works!
/* NEW VERSION, CHANGED TRIVIAL CASES TO EVALUATE N */
fib( N, 0) :-
N =:= 0.
fib( N, 1).
N =:= 1.
fib(N,F) :-
N > 1,
fib(N-1,F1),
fib(N-2,F2),
plus(F1,F2,F).
In prolog,
1 - 2
Doesn't actually do any arithmetic (I know, right?), it creates a structure:
-(1, 2)
And is is a predicate that evaluates that structure:
is(X, -(1, 2))
Will unify X with -1.
Also apparently < and > (and those like it) are like is in that they evaluate expressions.
So that means that the difference between your fib predicate and your line predicate is that
fib(0, 0).
is using unification, ie, testing whether the terms themselves are equal:
foo(0).
?- foo(1 - 1).
false
Whereas a test like =:= tests for numerical equality:
foo(X) :- X =:= 0.
?- foo(1 - 1).
yes
I'd probably write the predicate somthing like the following.
fib/2 is the outer 'public' interface. N is the position in the sequence (zero-relative). F gets unified with the value of the Fibonacci sequence at that position.
fibonacci/5 is the inner 'core' that does the work.
The 1st argument is the counter
The 2nd argument is the limit
The 3rd/4th arguments are the sliding frame required to compute the next item in the sequence. It should be noted that there is not required for a Fibonacci sequence start start with { 1 , 1 }. Any two integers will do.
The 5th argument gets unified with the desired result.
Each clause in the core works as follows:
If N is 0, F is unified with '1'.
If N is 1, F is unified with '1'.
If the limit has been reached, we're done. Unify F with the sum of the preceding two elements in the sequence.
If counter is less than the limit, compute the next element in the sequence and recurse, sliding the oldest value out from the sliding window.
Here's the code:
fib( N , F ) :-
N >= 0 ,
fibonnaci( 0 , N , 1 , 1 , F ).
fibonacci( 0 , 0 , F , _ , F ).
fibonacci( 1 , 1 , _ , F , F ).
fibonacci( Limit , Limit , X , Y , F ) :-
F is X + Y
.
fibonacci( Current , Limit , X , Y , F ) :-
Current < Limit ,
Next is Current + 1 ,
Z is X + Y ,
fibonacci( Next , Limit , Y , Z , F )
.

Resources