Prolog insert into a list - prolog

I would advice about this exercise:
Write a method insert, which has 3 parameters, the first an ordered
list, the second an int and the third an ordered list without repeated
values equal as the first one but containing the second parameter.
Example:
> insert([5, 6, 30, 60, 90], 40, L)
L = [5, 6, 30, 40, 60, 90]
> insert([5, 6, 30, 60, 90], 30, L)
L = [5, 6, 30, 60, 90]
I would do:
insert([],_,[_]).
insert([H],_,Result) :-
Result < H,
insert([],[],[Result|H]).
insert([H],_,Result) :-
Result > H,
insert([],[],[H|Result]).
insert([H,Y|Rest], _, Result):-
_ < Y,
insert([X|Rest], [], Result).
insert([H,Y|Rest], _, Result):-
_ > Y,
insert([Y|Rest], [], Result).
But I think base case when there is only one element is redundant and not needed because of we have the general recursive case and the empty list one. I need some suggest to improve or better explanations to polish the code.
Thank you for your time.

Try with compare:
:- use_module(library(clpfd)).
insert([], X, [X]).
insert([X|Xs], New, Ys) :-
zcompare(Order, X, New),
insert(Order, X, New, Xs, Ys).
insert(>, X, New, Xs, [New,X|Xs]).
insert(=, X, _, Xs, [X|Xs]).
insert(<, X, New, Xs, [X|Ys]) :-
insert(Xs, New, Ys).
but maybe you need explanation? It is strange, because you could also just read documentation as I did and find why this is good enough implementation, but of course maybe it is good to explain more, just in case.
insert([], X, [X]).
When first argument is empty list, second argument is the only element of the result list.
insert([X|Xs], New, Ys) :-
zcompare(Order, X, New), ...
When first argument is list with at least one element, take head element and compare it to New element. After compare or zcompare first argument Order is either > or = or < (but what do these mean? maybe guess or maybe even read documentation if it is not too much work).
insert(Order, X, New, Xs, Ys).
After comparing take the Order and the rest of the variables and....
insert(>, X, New, Xs, [New,X|Xs]).
Element at head of list is larger than New element. This means that result list should be New element followed by head followed by rest of list.
insert(=, X, _, Xs, [X|Xs]).
Element at head of list is exactly the same as New element. We are done, no need to insert anything just keep original list as result.
insert(<, X, New, Xs, [X|Ys]) :-
insert(Xs, New, Ys).
Element at head of list is smaller than New element: New element must come after this element in result. So we put current element back in list and search for place of New element in rest of list.
So much text, but is it now easier to understand what code says? Maybe or maybe not?
there
?- insert([5, 6, 30, 60, 90], 40, L).
L = [5, 6, 30, 40, 60, 90].
?- insert([5, 6, 30, 60, 90], 6, L).
L = [5, 6, 30, 60, 90].
?- insert([5, 6, 30, 60, 90], 100, L).
L = [5, 6, 30, 60, 90, 100].
?- insert([5, 6, 30, 60, 90], 0, L).
L = [0, 5, 6, 30, 60, 90].
but there are more interesting things to do with this solution because it uses a predicate like zcompare/3 which looks a bit like compare/3 but it knows integer constraints so it is possible to query:
What integers can be inserted in list [1,3,4]?
?- insert([1,3,4], X, R).
R = [X, 1, 3, 4],
X in inf..0 ;
X = 1,
R = [1, 3, 4] ;
X = 2,
R = [1, 2, 3, 4] ;
X = 3,
R = [1, 3, 4] ;
X = 4,
R = [1, 3, 4] ;
R = [1, 3, 4, X],
X in 5..sup.
So you can insert any integer < 1 at front, or you can "insert" 1 that was there, or you can insert 2 between 1 and 3, or you can "insert" 3 or 4, or you can insert 5 or anything larger at the end of list.

Another way :
% First element of the list is smaller than V
% we keep on wth the rest of the list
insert([H | T], V, [H|V1]) :-
H < V, !, % remove choice points
insert(T, V, V1).
% First element of the list is equal than V
% insert([V | T] , V, [V|T]).
% corrected after **enoy** remark
insert([V | T] , V, [V|T]):- !.
% First element of the list is greater than V, found the place of V
insert([H | T] , V, [V,H|T]).
% insert V in an empty list (V is greater than all elements of the list)
insert([], V, [V]).
with the same results as the Users9213 answer.
EDIT A way to avoid cut is
% First element of the list is smaller than V
% we keep on with the rest of the list
insert([H | T], V, [H|V1]) :-
H < V,
insert(T, V, V1).
% First element of the list is equal than V
insert([V | T] , V, [V|T]).
% First element of the list is greater than V, found the place of V
insert([H | T] , V, [V,H|T]):-
H > V.
% insert V in an empty list (V is greater than all elements of the list)
insert([], V, [V]).

Related

Turn List into number, increment the number, and then turn the number into a list

I have my head stuck in this exercise in prolog, I ve been trying to do it on my own but it just won't work. Example: ?-succesor([1,9,9],X) -> X = [2,0,0]. Had tried first to reverse the list and increment it with 1 and then do a if %10 = 0 the next element should be incremented too. Thing is that I m too used with programming syntax and I can't get my head wrapped around this.Any help would be appreciated.
I have done this so far, but the output is false.
%[1,9,9] -> 199 +1 -> 200;
numbers_atoms([],[]).
numbers_atoms([X|Y],[C|K]) :-
atom_number(C, X),
numbers_atoms(Y,K).
%([1,2,3],X)
digits_number(Digits, Number) :-
numbers_atoms(Digits, Atoms),
number_codes(Number, Atoms).
number_tolist( 0, [] ).
number_tolist(N,[A|As]) :-
N1 is floor(N/10),
A is N mod 10,
number_tolist(N1, As).
addOne([X],[Y]):-
digits_number(X,Y1), %[1,9,9] -> 199
Y1 is Y1+1, % 199 -> 200
number_tolist(Y1,[Y]), % 200 -> [2,0,0]
!.
You can solve this problem similarly to how you would solve it manually: traverse the list of digits until you reach the rightmost digit; increment that digit and compute the carry-on digit, which must be recursively propagated to the left. At the end, prepend the carry-on digit if it is equal to 1 (otherwise, ignore it).
% successor(+Input, -Output)
successor([X0|Xs], L) :-
successor(Xs, X0, C, Ys),
( C = 1 % carry-on
-> L = [C|Ys]
; L = Ys ).
% helper predicate
successor([], X, C, [Y]) :-
Z is X + 1,
Y is Z mod 10,
C is Z div 10. % carry-on
successor([X1|Xs], X0, C, [Y|Ys]) :-
successor(Xs, X1, C0, Ys),
Z is X0 + C0,
Y is Z mod 10,
C is Z div 10. % carry-on
Examples:
?- successor([1,9,9], A).
A = [2, 0, 0].
?- successor([2,7],A), successor(A,B), successor(B,C), successor(C,D).
A = [2, 8],
B = [2, 9],
C = [3, 0],
D = [3, 1].
?- successor([7,9,9,8], A), successor(A, B).
A = [7, 9, 9, 9],
B = [8, 0, 0, 0].
?- successor([9,9,9,9], A), successor(A, B).
A = [1, 0, 0, 0, 0],
B = [1, 0, 0, 0, 1].
Here's a version which doesn't use is and can work both ways:
successor(ListIn, ListOut) :-
reverse(ListIn, ListInRev),
ripple_inc(ListInRev, ListOutRev),
reverse(ListOutRev, ListOut).
ripple_inc([], [1]).
ripple_inc([0|T], [1|T]).
ripple_inc([1|T], [2|T]).
ripple_inc([2|T], [3|T]).
ripple_inc([3|T], [4|T]).
ripple_inc([4|T], [5|T]).
ripple_inc([5|T], [6|T]).
ripple_inc([6|T], [7|T]).
ripple_inc([7|T], [8|T]).
ripple_inc([8|T], [9|T]).
ripple_inc([9|T], [0|Tnext]) :-
ripple_inc(T, Tnext).
e.g.
?- successor([1,9,9], X).
X = [2, 0, 0]
?- successor([1,9,9], [2,0,0]).
true
?- successor(X, [2,0,0]).
X = [1, 9, 9]
although it's nicely deterministic when run 'forwards', it's annoying that if run 'backwards' it finds an answer, then leaves a choicepoint and then infinite loops if that choicepoint is retried. I think what causes that is starting from the higher number then reverse(ListIn, ListInRev) has nothing to work on and starts generating longer and longer lists both filled with empty variables and never ends.
I can constrain the input and output to be same_length/2 but I can't think of a way to constrain them to be the same length or ListOut is one item longer ([9,9,9] -> [1,0,0,0]).
This answer tries to improve the previous answer by #TessellatingHacker, like so:
successor(ListIn, ListOut) :-
no_longer_than(ListIn, ListOut), % weaker than same_length/2
reverse(ListIn, ListInRev),
ripple_inc(ListInRev, ListOutRev),
reverse(ListOutRev, ListOut).
The definition of no_longer_than/2 follows. Note the similarity to same_length/2:
no_longer_than([],_). % same_length([],[]).
no_longer_than([_|Xs],[_|Ys]) :- % same_length([_|Xs],[_|Ys]) :-
no_longer_than(Xs,Ys). % same_length(Xs,Ys).
The following sample queries still succeed deterministically, as they did before:
?- successor([1,9,9], X).
X = [2,0,0].
?- successor([1,9,9], [2,0,0]).
true.
The "run backwards" use of successor/2 now also terminates universally:
?- successor(X, [2,0,0]).
X = [1,9,9]
; false.

Exclude variants/rotations of lists in solutions SWI-Prolog

I want to exclude multiple rotations/mirrors of a list in my solutions of the predicate. I'll give an example of what I understand are rotations/mirrors of a list:
[1,2,3,4,5]
[2,3,4,5,1]
[3,4,5,1,2]
[5,4,3,2,1]
I have to find a predicate that delivers unique sequence of numbers from 1 to N, according to some constraints. I already figured out how to compute the right sequence but I can't find out how to exclude all the rotations and mirrors of 1 list. Is there an easy way to do this?
Edit:
Full predicate. clock_round(N,Sum,Yf) finds a sequence of the numbers 1 to N in such a way that no triplet of adjacent numbers has a sum higher than Sum.
clock_round(N,Sum,Yf) :-
generate(1,N,Xs),
permutation(Xs,Ys),
nth0(0,Ys,Elem1),
nth0(1,Ys,Elem2),
append(Ys,[Elem1,Elem2],Ym),
safe(Ym,Sum),
remove_duplicates(Ym,Yf).
remove_duplicates([],[]).
remove_duplicates([H | T], List) :-
member(H, T),
remove_duplicates( T, List).
remove_duplicates([H | T], [H|T1]) :-
\+member(H, T),
remove_duplicates( T, T1).
% generate/3 generates list [1..N]
generate(N,N,[N]).
generate(M,N,[M|List]) :-
M < N, M1 is M + 1,
generate(M1,N,List).
% permutation/2
permutation([],[]).
permutation(List,[Elem|Perm]) :-
select(Elem,List,Rest),
permutation(Rest,Perm).
safe([],_).
safe(List,Sum) :-
( length(List,3),
nth0(0,List,Elem1),
nth0(1,List,Elem2),
nth0(2,List,Elem3),
Elem1 + Elem2 + Elem3 =< Sum
; [_|RestList] = List, % first to avoid redundant retries
nth0(0,List,Elem1),
nth0(1,List,Elem2),
nth0(2,List,Elem3),
Elem1 + Elem2 + Elem3 =< Sum,
safe(RestList,Sum)
).
So what you want is to identify certain symmetries. At first glance you would have to compare all possible solutions with such. That is, in addition of paying the cost of generating all possible solutions you will then compare them to each other which will cost you a further square of the solutions.
On the other hand, think of it: You are searching for certain permutations of the numbers 1..n, and thus you could fix one number to a certain position. Let's fix 1 to the first position, that is not a big harm, as you can generate the remaining n-1 solutions by rotation.
And then mirroring. What happens, if one mirrors (or reverses) a sequence? Another sequence which is a solution is produced. The open question now, how can we exclude certain solutions and be sure that they will show up upon mirroring? Like: the number after 1 is larger than the number before 1.
At the end, rethink what we did: First all solutions were generated and only thereafter some were removed. What a waste! Why not avoid to produce useless solutions first?
And even further at the end, all of this can be expressed much more efficiently with library(clpfd).
:- use_module(library(clpfd)).
clock_round_(N,Sum,Xs) :-
N #=< Sum, Sum #=< 3*N -2-1,
length(Xs, N),
Xs = [D,E|_],
D = 1, append(_,[L],Xs), E #> L, % symmetry breaking
Xs ins 1..N,
all_different(Xs),
append(Xs,[D,E],Ys),
allsums(Ys, Sum).
allsums([], _).
allsums([_], _).
allsums([_,_], _).
allsums([A,B,C|Xs], S) :-
A+B+C #=< S,
allsums([B,C|Xs], S).
?- clock_round_(N, Sum, Xs), labeling([], [Sum|Xs]).
N = 3, Sum = 6, Xs = [1,3,2]
; N = 4, Sum = 9, Xs = [1,3,4,2]
; N = 4, Sum = 9, Xs = [1,4,2,3]
; N = 4, Sum = 9, Xs = [1,4,3,2]
; N = 5, Sum = 10, Xs = [1,5,2,3,4]
; ... .
Here is a possibility do do that :
is_rotation(L1, L2) :-
append(H1, H2, L1),
append(H2, H1, L2).
is_mirror(L1, L2) :-
reverse(L1,L2).
my_filter([H|Tail], [H|Out]):-
exclude(is_rotation(H), Tail, Out_1),
exclude(is_mirror(H), Out_1, Out).
For example
?- L = [[1,2,3,4,5],[2,3,4,5,1],[3,4,5,1,2],[5,4,3,2,1], [1,3,2,4,5]],my_filter(L, Out).
L = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 1], [3, 4, 5, 1, 2], [5, 4, 3, 2, 1], [1, 3, 2, 4|...]],
Out = [[1, 2, 3, 4, 5], [1, 3, 2, 4, 5]].

Prolog: List of sublists

i have a task to create a list of sublists where the elements are sorted in consecutive order. I'm having difficulties because when it iterates through the list and returns multiple lists with a list, thats not what i want. My goal is a list with multiple sublists of length 3.
example
list([]).
list([_|T]) :- list(T).
sublist(L, []) :- list(L).
sublist([HX|TX],[HX|TY]) :- sublist(TX,TY).
sublist([_|TY], X) :- X = [_|_], sublist(TY, X).
This prints out every single sublist.
?- sublist([10,20,30,a,b], L).
L = [] ;
L = [10] ;
L = [10, 20] ;
L = [10, 20, 30] ;
L = [10, 20, 30, a] ;
L = [10, 20, 30, a, b] ;
L = [10, 20, 30, b] ;
..and so on
What i want is something like this
?- sublist([10,20,30,a,b], L).
L = [[10,20,30],[20,30,a],[30,a,b]]
I've been overthinking this i guess, and other thing X = [_,_,_] destroys my functionality.
You can use append/3 to obtain all the "sliding" sublists.
For the specific case of 3 elements:
sublist(L, LSubL):-
findall([A,B,C], append(_, [A,B,C|_], L), LSubL).
For the more general case of sliding window of 'Size' items:
sliding_window(L, Size, LSubL):-
length(SubL, Size),
append(SubL, _, SubLO),
findall(SubL, append(_, SubLO, L), LSubL).

I don't know how to stop this from going into a loop

The question was to create a replace/4 predicate that would replace a certain element (X) from the first list with another element (Y) like x and finally store it into the last argument, a new list. I know there is obviously something wrong with my base case (?), but I can't seem to figure it out. When I trace this code, it starts of normal, but after the first list is empty, it starts adding anonymous variables. Please have mercy, I'm new to Prolog.
replace([], _, _, []).
replace([H|T], X, Y, N):-
H = X,
append(N, [Y], NL),
replace(T, X, Y, NL).
replace([H|T], X, Y, N):-
H \= X,
append(N, [H], NL),
replace(T, X, Y, NL).
A simple more efficient solution without append/3 would be:
replace([], _, _, []).
replace([X|T], X, Y, [Y|T1]):-replace(T, X, Y, T1).
replace([H|T], X, Y, [H|T1]):-dif(X,H), replace(T, X, Y, T1).
Note that it is much better to use predicate dif/2 instead of \= operator (it has more relational behavior: Just test dif(X,Y). and X\=Y. with X,Y unbound variables to see the difference).
Example:
?- replace([2,4,5,7,8,2,3,4],2,12,L).
L = [12, 4, 5, 7, 8, 12, 3, 4] ;
false.
Another solution would be using DCG:
replace([],_,_) -->[].
replace([X|T],X,Y) --> [Y],replace(T,X,Y).
replace([H|T],X,Y) --> [H],{dif(H,X)},replace(T,X,Y).
final_replace(In_L,X,Y,Out_L):- phrase(replace(In_L,X,Y),Out_L).
Example:
?- final_replace([2,4,5,7,8,2,3,4],2,12,L).
L = [12, 4, 5, 7, 8, 12, 3, 4] ;
false.

Create a list from zero down to a negative number

I want to make a program in which the user will give a negative number and it will return a list starting from zero till that number. Here is a desired output example
create(-5,L).
L = [0,-1,-2,-3,-4,-5]
could you help me in any way, please?
I would break it up into two auxiliary predicates. The auxiliary predicate is helpful for building the list in the direction you desire.
create(N, L) :-
N < 0,
create_neg(N, 0, L).
create(N, L) :-
N >= 0,
create_pos(N, 0, L).
create_neg(N, N, [N]).
create_neg(N, A, [A|T]) :-
A > N,
A1 is A - 1,
create_neg(N, A1, T).
create_pos(N, N, [N]).
create_pos(N, A, [A|T]) :-
A < N,
A1 is A + 1,
create_pos(N, A1, T).
This will put them in the right order as well:
| ?- create(-5, L).
L = [0,-1,-2,-3,-4,-5] ? a
no
| ?- create(5, L).
L = [0,1,2,3,4,5] ? a
no
| ?-
What you're after is not really a program, just an 'idiomatic' pattern:
?- findall(X, (between(0,5,T), X is -T), L).
L = [0, -1, -2, -3, -4, -5].
Note the parenthesis around the Goal. It's a compound one...
Another way:
?- numlist(-5,0,T), reverse(T,L).
...
Since you provided your code (which as mentioned in comments would be better to appear in your question), one problem I think is that with X>0 and X<0 clauses-cases you will have infinite recursion, maybe it would be better to use abs/1:
create(0,[0]).
create(X,[X|T]):- Y is abs(X), Y > 0,
(X>0 -> N is X-1 ; N is X+1),
create(N,T).
Though still one problem:
?- create(-5,L).
L = [-5, -4, -3, -2, -1, 0] ;
false.
?- create(5,L).
L = [5, 4, 3, 2, 1, 0] ;
false.
The list is built reversed so you could reverse it at the end like:
create_list(N,L):- create(N,L1), reverse(L1, L).
And now:
?- create_list(5,L).
L = [0, 1, 2, 3, 4, 5] ;
false.
?- create_list(-5,L).
L = [0, -1, -2, -3, -4, -5] ;
false.

Resources