Related
I am trying to decode a specific list with two different elements, either e.g. [4, a] or just b
I expect decode([[4,a],b,[2,c],[2,a],d,[4,e]], X). to result into X=[a,a,a,a,b,c,c,a,a,d,e,e,e,e].
with
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, L1),
append(L1, R),
decode(Xs, R).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, []).
create_list(N, X, [X|R]) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R).
Generates only false and I have tested the create_list predicate and it works.
I have no clue what I'm missing but could just be a minor mistake. But I have tried for a while to find the problem without success so why not ask here :) The question is a modified version from the Ninety-Nine Prolog Problems (Problem 12).
Your problem lies in the use of append/2 which concatenates a list of lists, but you have a list of atoms.
You may use append/3 to build a list with an unbound tail and pass that tail to the recursive step of your procedure, i.e.:
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, L1),
append(L1, Tail, R),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, []).
create_list(N, X, [X|R]) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R).
Sample run:
?- decode([[4,a],b,[2,c],[2,a],d,[4,e]], X).
X = [a, a, a, a, b, c, c, a, a, d, e, e, e, e] ;
false.
You may also get rid of append altogether by adding a third argument to create_list which holds that tail:
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, R, Tail),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, Tail, Tail).
create_list(N, X, [X|R], Tail) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R, Tail).
Alternatively you may get rid of create_list by using length/2 and maplist/2:
decode([], []).
decode([[N, X]|Xs], R) :-
length(L, N),
maplist(=(X), L),
append(L, Tail, R),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
This is a problem of run-length encoding and run-length decoding.
Run-length encoding is easy:
encode( [] , [] ) . % the run-length encoding of the empty list is the empty list
encode( [X|Xs] , [R|Ys] ) :- % For non-empty lists,
run(Xs,X:1,R,Rs), % - seed the run with the first element and compute the run length
encode(Rs, Ys) % - then recurse down
. % Easy!
run( [] , Y:N , Y:N , [] ) .
run( [X|Xs] , Y:N , Y:N , [X|Xs] ) :- X \== Y .
run( [X|Xs] , Y:T , N , Rs ) :- X == Y , T1 is T+1 , run(Xs,Y:T1,N,Rs) .
And decoding a run-length encoded list is the opposite
decode( [] , [] ) . % the run-length decoding of the empty list is the empty list
decode( [X:N|Xs] , Ys ) :- % for non-empty lists,
expand(X,N,Ys,Zs) , % - expand the run
decode(Xs,Zs) % - recurse down
.
expand( _ , 0 , Zs , Zs ) .
expand( X , N , [X|Ys] , Zs ) :-
N > 0,
N1 is N-1,
expand(X,N1,Ys,Zs)
.
And then put it together in a transcoder that will work bi-directionally:
run_length_transcode( PlainText, RleText ) :- nonvar( PlainText ) , encode( PlainText , RleText ).
run_length_transcode( PlainText, RleText ) :- nonvar( RleText ) , decode( RleText , PlainText ).
I should remove all elements of List that are not a number greater than number. I can solve it just for numbers. but when the list has some symbolic how should I delete.this is my code
greater_nrs_only( X, List, Ans) :-
greater_nrs_only( X, List, Ans, [] ), !.
greater_nrs_only( _, [], Ans, Ans).
greater_nrs_only( X, [H | Tail], Ans, Acc ) :-
(
( H < X, NewEl = [] )
;
( H >= X, NewEl = [H] )
),
append( Acc, NewEl, NewAcc ),
greater_nrs_only( X, Tail, Ans, NewAcc).
and ?- greater_nrs_only(6, [ ], X).
is false
The reason this will error is because H is not per se a number, so comparing 6 with a for example will raise an error. You can use number/1 [swi-doc] to check if something is a number.
Instead of doing filtering manually, you can also work with include/3 [swi-doc], which filters the list for items that satisfy a given predicate:
greater_than(X, Y) :-
number(Y),
X < Y.
greater_nrs_only(X, L, R) :-
include(greater_than(X), L, R).
I have a problem in Prolog.
Consider a list where each element is referring to a position/location in the same list.
I want to write a program which returns true if I start with the same location that I end in. For example:
If I give it find-s([3,2,0,1],0)
It starts with 0 index which contains 3
then goes to the 3 index which contains 1
then the 1 index to find 2
finally to index 2 which contains 0 !
so it returns true in this case
I tried this but it didn't work
position([Head1| Tail1], Var1) :-
( Head1 == Var1,
Tail1 == Var1 ->
true
).
this should work
find_s(L, S) :- nth0(S, L, I), find_s(L, I, S).
find_s(_, S, S).
find_s(L, I, S) :- nth0(I, L, J), find_s(L, J, S).
but I think it could easily loop. So, instead of nth0/3, let's use nth0/4, after this consideration:
?- nth0(2,[a,b,c,d],X,Y).
X = c,
Y = [a, b, d].
?- nth0(2,L,$X,$Y).
L = [a, b, c, d].
for sake of readability, let's introduce a replace_nth0/4
replace_nth0(P, L, E, LrepE) :-
nth0(P, L, E, L_Without_E),
nth0(P, LrepE, -1, L_Without_E).
and then
find_s(L, S) :- nth0(S, L, I), find_s(L, I, S).
find_s(_, S, S).
find_s(L, I, S) :- I >= 0, replace_nth0(I, L, J, L_rep), find_s(L_rep, J, S).
I am trying to solve the Magic Hexagon problem in Prolog, in dimension 5, for now(?). I first create the layout, by using a 2D list. Then I try to constraint every element of that list (which is actually a list).
However, I can't make it work, here is my code, after all the updates:
:- use_module(library(clpfd)).
solve(Dim) :-
length(L, 5), % define 5 diagonals
Offset is Dim - 2,
Flag is 0,
fill(L, Offset, Dim, Flag),
writeln(L),
constraint_sum(L, 38),
writeln(L).
constraint_sum([], _).
constraint_sum([H|T], Sum) :-
label(H),
sum_list(H, Sum),
constraint_sum(T, Sum).
fill([], _, _, _).
fill([H|T], Len, Dim, Flag) :-
Flag == 0,
Len < Dim,
length(H, Len),
H ins 1..19,
all_different(H),
NewLen is Len + 1,
fill(T, NewLen, Dim, Flag).
fill([H|T], Len, Dim, _) :-
length(H, Len),
H ins 1..19,
all_different(H),
NewLen is Len - 1,
Flag is 1,
fill(T, NewLen, Dim, Flag).
and I am getting:
1 ?- solve(5).
[[_G2537,_G2581,_G2617],[_G2857,_G2893,_G2929,_G2965],
[_G3263,_G3299,_G3335,_G3371,_G3407],[_G3757,_G3793,_G3829,_G3865],
[_G4157,_G4193,_G4229]]
[[1,18,19],[1,2,16,19],[1,2,3,13,19],[1,2,16,19],[1,18,19]]
true .
..as you can see the problem is that the elements are not unique, since I have used all_different() for every list separately and not for the whole list, but I do not know how do that!
my bet - but I think there is a bug, since the problem page states there is only a solution.
:- module(magic_exagon, [magic_exagon/0]).
:- use_module(library(clpfd)).
magic_exagon :-
magic_exagon(3, 38).
magic_exagon(N, Sum) :-
R is N*2-1,
findall(L, (between(1,R,C), c_cells(C,N,R,L)), Rows),
flatten(Rows, Cells),
length(Cells, Max),
Cells ins 1..Max,
all_different(Cells),
get_diags(Rows, N,R,1, LeftDiags),
reverse(Rows, Rev),
maplist(reverse, Rev, RevRows),
get_diags(RevRows, N,R,1, RightDiags),
maplist(sum_diags(Sum), Rows),
maplist(sum_diags(Sum), LeftDiags),
maplist(sum_diags(Sum), RightDiags),
label(Cells),
show(rows, Rows).
c_cells(C,N,R,L) :-
( C > N -> M is N+R-C ; M is N+C-1 ),
length(L,M).
sum_diags(Sum, Diag) :-
sum(Diag, #=, Sum).
get_diags([], _,_,_, []).
get_diags(Rows, N,R,C, [Diag|Diags]) :-
c_cells(C, N, R, Diag),
capture(Diag, Rows, RestWithEmpty),
drop_empties(RestWithEmpty, Rest),
C1 is C+1,
get_diags(Rest, N,R,C1, Diags).
capture([], Rest, Rest).
capture([Cell|Diag], [[Cell|Cs]|Rows], [Cs|Rest]) :-
capture(Diag, Rows, Rest).
drop_empties([[]|RestT], Rest) :- !, drop_empties(RestT, Rest).
drop_empties(Rest, Rest).
show(K,Ds) :- writeln(K), maplist(writeln, Ds).
get_diags/5 is tricky to do with indexing. I devised an algorithm to capture a diag from the playground. We cannot use findall/3 after variables have been attributed, hence the recursive loop.
edit
To display diagonals, an easy way
...
label(Cells),
show(rows, Rows),
show(left, LeftDiags),
show(right, RightDiags).
and we get
?- magic_exagon.
rows
[3,16,19]
[17,6,7,8]
[18,4,1,5,10]
[12,2,11,13]
[9,14,15]
left
[3,17,18]
[16,6,4,12]
[19,7,1,2,9]
[8,5,11,14]
[10,13,15]
right
[15,13,10]
[14,11,5,8]
[9,2,1,7,19]
[12,4,6,16]
[18,17,3]
So I have this homework due tommorow. I have to filter every nth element of a list and return it as a list. So for example:
?- everyNth(3,[a,b,c,d,e,f],Rs).
Rs = [c,f].
My Idea was basically:
everynth(N, [X|Xs], L) :- everynth(N, [X|Xs], N, L).
everynth(N, [], C, L).
everynth(N, [X|Xs], 0, [X]) :- everynth(N, Xs, N, [X]).
everynth(N, [X|Xs], C, L) :- C1 is C -1,
everynth(N,Xs,C1,L).
But it does not work this way, because in the third row it tries to match X and the return X and the Count 0 the second time it goes there.
You are almost there. Check these modifications:
everynth(N, L, NL) :- everynth(N, L, N, NL).
everynth(_, [], _, []).
everynth(N, [X|Xs], 1, [X|NXs]) :- everynth(N, Xs, N, NXs).
everynth(N, [_|Xs], C, NXs) :- C1 is C-1, C1>0,
everynth(N,Xs,C1,NXs).
The first clause of everynth/4 is the termination of the recursion. It should give an empty list when there are no more items in the input list.
The second clause of everynth/4 deals with the nth item, it has to put the input item in the output list and keep processing the remaining items restarting your item counter.
And the third clause of everynth/4 deals with items which are not the nth element, so you have to skip the item, decrement the counter and continue with the remaining items.
everynth(_, _, [], R, R).
everynth(1, M, [X|Xs], Z, R) :- append(Z, [X], Z1), everynth(M, M, Xs, Z1, R).
everynth(N, M, [_|Xs], Z, R) :- N > 1, N1 is N - 1, everynth(N1, M, Xs, Z, R).
?- everynth(3, 3, [a,b,c,d,e,f], [], Rs).
Rs = [c, f] .