Related
i have the following
fnf([],[],[]).
fnf([RH|RT],[CH|CT],[[RH,CH]|Res]) :- get(RH,CH,V), V == 0, fnf(RT,CT,Res).
i'm trying to collect only elements of Cs and Rs for which the V is zero.
The code above does that but fails when it hits non-zero value.
I want to just skip them, instead of failing the whole goal.
this sort of works
fnf([RH|RT],[CH|CT],[[RH,CH]|Res]) :- get(RH,CH,V), ( V == 0 -> fnf(RT,CT,Res);true).
still _2044 !! should not be there
F = [[1, 1], [2, 2]|_2044].
If you want to test only once (get/3 + condition) and then keep the item or skip it and continue recursion you can use an if-then-else construct like so:
fnf([], [], []).
fnf([RH|RT], [CH|CT], Res) :-
get(RH, CH, V),
( V==0 % test
-> Res=[[RH, CH]|Res1] % condition met, keep item
; Res=Res1 % condition not met, skip item
),
fnf(RT, CT, Res1).
Also note the call to get/3 may backtrack if it leaves choicepoints.
How about adding a case for 0 and a case for non-zero:
fnf([],[],[]).
fnf([RH|RT],[CH|CT],[[RH,CH]|Res]) :-
get(RH,CH,0),
fnf(RT,CT,Res).
fnf([_|RT],[_|CT],Res) :-
get(RH,CH,V),
dif(V, 0),
fnf(RT,CT,Res).
or
pairs_keys_values(Pairs, Rs, Cs),
findall([RH,CH], (member(RH-CH, Pairs), get(RH, CH, 0)), F).
I want to implement a predicate P(Xs,Ys,Zs) where Xs,Ys,Zs are lists.
I'm new in Prolog and I can't find a way to get to the longest sequence in Xs (example. Xs = ['b','b','A','A','A','A','b','b']) which is included to Ys (for example Ys = ['A','A','A','A','c','A','A','A','A']) without crossing- an even number of times. Maybe someone already wrote this code ore some one can say me how can I start. Thanks for helps.
explanation of teacher.
longest_subsequence(List, Part, Subsequence):-
longest_subsequence_(List, Part, [], Subsequence).
longest_subsequence_(Xs, Ys, CurrentSubsequence, LongestSubsequence):-
append(CurrentSubsequence, Ys, NextSubsequence),
divide_list(Xs, [_LeftYs, NextSubsequence, _RightYs]), !,
longest_subsequence_(Xs, Ys, NextSubsequence, LongestSubsequence).
longest_subsequence_(_Xs, _Ys, LongestSubsequence, LongestSubsequence).
okey i did.
main_task(Xs, Ys, Zs) :-
atom_chars(Xs, Xl),
atom_chars(Ys, Yl),
retractall(record(_, _)),
assert(record(0, [])),
process(Xl, Yl, Zl),
atom_chars(Zs, Zl).
process(Xl, Yl, _) :-
get_sublist(Xl, Zl),
length(Zl, L),
record(MaxL, _),
L > MaxL,
get_index(Yl, Zl, Il),
test_even(Il),
test_intersect(Il, L),
retractall(record(_, _)),
assert(record(L, Zl)),
fail.
process(_, _, Zl) :-
record(_, Zl).
get_sublist(L1, L2) :-
get_tail(L1, L3),
get_head(L3, L2).
get_tail(L, L).
get_tail([_|T], L) :-
get_tail(T, L).
get_head([H|T1], [H|T2]) :-
get_head(T1, T2).
get_head(_, []).
get_index(Yl, Zl, Il) :-
get_index(Yl, Zl, Il, 0).
get_index([], _, [], _).
get_index([Yh|Yt], Zl, [I|It], I) :-
get_head([Yh|Yt], Zl),
!,
I1 is I + 1,
get_index(Yt, Zl, It, I1).
get_index([_|Yt], Zl, Il, I) :-
I1 is I + 1,
get_index(Yt, Zl, Il, I1).
test_even(Il) :-
length(Il, L),
L > 0,
L mod 2 =:= 0.
test_intersect([_], _).
test_intersect([X,Y|T], L) :-
Y - X >= L,
test_intersect([Y|T], L).
All lines in the list at the symbols on working with lists
Initialize the dynamic database - will be stored in it, and its maximum line length
enumerates all of the substring (sublists) from X. Bust goes double "pruning" - first place in a list of cut off the front, then from behind.
Check the length of the resulting string, if we already have a long, immediately leave for the continuation of busting
We consider a list of indexes in the occurrence of a Y, then there is every element of the list - a position in the Y, from which it includes Z.
Check the parity - just consider the length of the list of indexes, chёtnaya length - an even number of entries. And we need to check that it is greater than zero.
Check the intersection - you need to check the difference between two adjacent elements of the list of indexes, the difference should always be greater than the length Z.
If all checks are made, there is a dynamic database updates - current list Z is stored as the maximum
At the end it is a forced failure, it is rolled back to the fork in paragraph 3) and the continued search.
Note: If any check is not performed, the failure of this test is immediately rolled back to the fork in paragraph 3) and the continued search.
When the bust comes to an end, performed a second rule predicate process, it simply selects the last spicok Z in the base.
At the end of the list Z is converted back to a string
A naive approach is the following:
longest_subsequence(Xs,Ys,Zs) :-
longest_subsequence(Xs,Ys,Ys,0,[],Zs).
longest_subsequence([X|Xs],Y0,[Y|Ys],N0,Z0,Z) :-
try_seq([X|Xs],[Y|Ys],Nc,Zc),
(Nc > N0
-> longest_subsequence([X|Xs],Y0,Ys,Nc,Zc,Z)
; longest_subsequence([X|Xs],Y0,Ys,N0,Z0,Z)
).
longest_subsequence([_|Xs],Y0,[],N0,Z0,Z) :-
longest_subsequence(Xs,Y0,Y0,N0,Z0,Z).
longest_subsequence([],_,_,_,Z,Z).
try_seq([H|TA],[H|TB],N,[H|TC]) :-
!,
try_seq(TA,TB,N1,TC),
N is N1+1.
try_seq(_,_,0,[]).
here a predicate try_seq/3 aims to match as much as possible (generate the longest common subsequence) starting from the beginning of the list.
The problem is that this is a computationally expensive approach: it will have a time complexity O(m n p) with n the length of the first list, m the length of the second list and p the minimum length of the two lists.
Calling this with your example gives:
?- longest_subsequence([b,b,a,a,a],[a,a,a,c,a,a,a],Zs).
Zs = [a, a, a] ;
false.
You can make the algorithm more efficient using back-referencing, this is more or less based on the Knuth-Morris-Pratt-algorithm.
When approaching a problem, first try: divide and conquer.
When we have a list_subsequence(+List, ?Subsequence) predicate
list_subsequence([H|T], S) :-
list_subsequence(H, T, S, _).
list_subsequence([H|T], S) :-
list_subsequence(H, T, _, R),
list_subsequence(R, S).
list_subsequence(H, [H|T], [H|S], R) :- !, list_subsequence(H, T, S, R).
list_subsequence(H, R, [H], R).
we can call for library(aggregate) help:
longest_subsequence(Seq, Rep, Longest) :-
aggregate(max(L, Sub), N^(
list_subsequence(Seq, Sub),
aggregate(count, list_subsequence(Rep, Sub), N),
N mod 2 =:= 0,
length(Sub, L)
), max(_, Longest)).
edit: more library support available
A recently added library helps:
longest_subsequence_(Seq, Rep, Longest) :-
order_by([desc(L)], filter_subsequence(Seq, Rep, Longest, L)), !.
where filter_subsequence/4 is simply the goal of the outer aggregate:
filter_subsequence(Seq, Rep, Sub, L) :-
list_subsequence(Seq, Sub),
aggregate(count, list_subsequence(Rep, Sub), N),
N mod 2 =:= 0,
length(Sub, L).
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]
I have been brushing up on some Prolog recently. I kind of enjoy just coming up with random problems to try and solve and then working them out. This one is quite tough though, and I'm not one to give up on a problem that I have set out to solve.
The problem: I want to make a predicate that will have 2 predetermined lists, 2 numbers to swap, and then output the lists after the swapping is done.
Further Explanation: I made it a little harder on myself by wanting to find a specific unique number from list 1, and swapping this with a specific unique number from list 2 so that if I have 2 lists...
[7,2,7,8,5], and [1,2,3,8,7,9,8], and then give the predicate 2 numbers(Lets just say 8 and 7), then the number 8 and the number 7 will be swapped between the lists IF AND ONLY IF the number 8 is in the first list and the number 7 is in the second list. (It would disregard an 8 in the second list and a 7 in the first list).
Sample query with expected answer:
?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8],8,7,X,Y).
X = [7,2,7,7,5], Y = [1,2,3,8,8,9,8].
I kind of got stuck at this point:
bothSwap([],L2,N1,N2,[],L2).
bothSwap(L1,[],N1,N2,L1,[]).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 == N2, bothSwap(T1,T2,N1,N2,D1,D2), append(D1,[H2],X), append(D2,[H1],Y).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 =\= N2, bothSwap([H1|T1],T2,N1,N2,D1,D2).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 =\= N1, H2 == N2, bothSwap(T1,[H2|T2],N1,N2,D1,D2).
Any bright minds out there willing to tackle this problem with me? :)
Imagine how easy this problem would be if we could just "wish" for a list to be split up at the occurrence of the desired element, like this:
?- splitsies([1,2,3,4,5,6,7,8], 4, Prefix, Suffix).
Prefix = [1, 2, 3],
Suffix = [5, 6, 7, 8] ;
Guess what? :) append/3 can do that:
% splitsies is true if X splits list into a prefix/suffix pair.
splitsies(List, X, Start, Finish) :-
append(Start, [X|Finish], List).
Now the problem seems pretty simple!
bothSwap(Left, Right, A, B, AfterLeft, AfterRight) :-
% break up the inputs
splitsies(Left, A, LPre, LPost),
splitsies(Right, B, RPre, RPost),
% glue together the outputs (note that A and B are switched)
splitsies(AfterLeft, B, LPre, LPost),
splitsies(AfterRight, A, RPre, RPost).
I wouldn't pretend that this solution is efficient… but it's so hot you better wear oven mitts when you type it in. Oh, and check this out:
?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8], X, Y, [7,2,7,7,5], [1,2,3,8,8,9,8]).
X = 8,
Y = 7 ;
false.
Let's start, what you mean by swapping.
swap(X0,X, S0,S) :-
if_(X0 = S0, S = X, S = S0).
bothSwap0(Xs0, Ys0, X0,X, Xs,Ys) :-
maplist(swap(X0,X), Xs0,Xs),
maplist(swap(X,X0), Ys0,Ys).
if_( C_1, Then_0, Else_0) :-
call(C_1, Truth),
functor(Truth,_,0), % safety check
( Truth == true -> Then_0 ; Truth == false, Else_0 ).
=(X, Y, R) :- X == Y, !, R = true.
=(X, Y, R) :- ?=(X, Y), !, R = false. % syntactically different
=(X, Y, R) :- X \= Y, !, R = false. % semantically different
=(X, Y, R) :- R == true, !, X = Y.
=(X, X, true).
=(X, Y, false) :-
dif(X, Y).
Now you wanted a particular condition - it is not clear how to apply it. I see two interpretations:
bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
memberd(X0, Xs0),
memberd(X, Ys0),
maplist(swap(X0,X), Xs0,Xs),
maplist(swap(X,X0), Ys0,Ys).
Which means that bothSwap/6 will fail should the two elements not occur in their respective list.
Another interpretation might be that you want that otherwise the lists remain the same. To express this (in a pure monotonic fashion):
bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
if_( ( memberd_t(X0, Xs0), memberd_t(X, Ys0) ),
( maplist(swap(X0,X), Xs0,Xs), maplist(swap(X,X0), Ys0,Ys) ),
( Xs0 = Xs, Ys0 = Ys) ).
memberd_t(E, Xs, T) :-
list_memberd(Xs, E, T).
list_memberd([], _, false).
list_memberd([X|Xs], E, T) :-
if_(E = X, T = true, list_memberd(Xs, E, T) ).
','( A_1, B_1, T) :-
if_( A_1, call(B_1, T), T = false ).
Since Prolog is a descriptive language (that is, we describe what constitutes a solution and let Prolog work it out), If I understand your problem statement correctly, something like this ought to suffice:
both_swap(L1, L2, A, B, S1, S2 ) :- % to do the swap,
memberchk(A,L1) , % - L1 must contain an A
memberchk(B,L2) , % - L2 must contain a B
replace(L1,A,B,S1) , % - replace all As in L1 with a B
replace(L2,B,A,S2) % - replace all Bs in L2 with an A
. % Easy!
replace([],_,_,[]) . % if the list is empty, we're done.
replace([H|T],A,B,[S|Ss]) :- % otherwise...
( H = A -> S=B ; S=H ) , % - do the swap (if necessary),
replace(T,A,B,Ss) % - and recurse down
. % Also easy!
This replicates the implementation that uses splitsies/4
swap_two(A,B,C,D,E,F) :-
nth0(I1,A,C,L1),
dif(A,L1),
nth0(I2,B,D,L2),
dif(B,L2),
nth0(I1,E,D,L1),
nth0(I2,F,C,L2).
I have a list of lists, and I need to find the longest one of them. If there are more than one with the same length it's the same which it returns. Thanks.
Here is a general predicate that scans a list to find a single member defined by a given goal.
select_element(Goal, [Head | Tail], Selected) :-
select_element(Goal, Tail, Head, Selected).
select_element(_Goal, [], Selected, Selected).
select_element(Goal, [Head | Tail], Current, FinalSelected) :-
call(Goal, Head, Current, Selected),
select_element(Goal, Tail, Selected, FinalSelected).
Lets say you define a predicate
get_bigger_number(N1, N2, N) :-
N is max(N1, N2).
Now you can execute:
?- select_element(get_bigger_number, [5, 1, -2, 10, 3.2, 0], Selected).
Selected = 10
So all you need to do now is define a predicate get_longer_list(L1, L2, L),
and use it instead of get_bigger_number/3.
Of course, using a general predicate like select_element/3 might not be very efficient. For example, you should try to avoid calculating the length of the same list several times, because this calculation is slow in Prolog (at least if implemented in Prolog in the standard way).
Please consider my aproach.
longest([L], L) :-
!.
longest([H|T], H) :-
length(H, N),
longest(T, X),
length(X, M),
N > M,
!.
longest([H|T], X) :-
longest(T, X),
!.
Then you can consult it:
?- longest([[1]], N).
N = [1] ;
?- longest([[1],[2]], N).
N = [2] .
?- longest([[1],[2], [3,3,3], [2]], N).
N = [3, 3, 3] ;
?- longest([[1],[2], [3,3,3], [2]], N).
N = [3, 3, 3].
?- longest([[1],[2], [3,3,3], [2], [4,4,4,4]], N).
N = [4, 4, 4, 4] .
?- longest([[1],[2], [3,3,3], [2], [4,4,4,4]], N).
N = [4, 4, 4, 4] ;
Greets!
We define longest/2 based on meta-predicate max_of_by/3 used in tandem with length/2:
longest(Xss,Ys) :-
max_of_by(Ys,Xss,length).
Sample queries:
?- longest([[1],[2]],Xs). % we expect multiple solutions
Xs = [1]
; Xs = [2]. % we _get_ multiple solutions
?- longest([[2,1,3],[7,5],[1,8,2,3,1],[2,7,1,4]],Xs).
Xs = [1,8,2,3,1]. % succeeds deterministically
Here is another approach that is efficient and easy to understand. The idea is to find the lengths of all lists in the list, use max_list to get the length of the longest list, and then find a list that is that long. This has the benefit that it will return all lists of the longest length.
lengths([],[]).
lengths([H|T], [LH|LengthsT]) :-
length(H, LH),
lengths(T, LengthsT).
lengthLongest(ListOfLists, Max) :-
lengths(ListOfLists, Lengths),
max_list(Lengths, Max).
longestList(ListOfLists, Longest) :-
lengthLongest(ListOfLists, Len),
member(Longest, ListOfLists),
length(Longest, Len).
% Correct again.
longest(LL,LX) :-
findmax(Len,(append(_,[L|_],LL),length(L,Len)),MaxLen),
append(_,[LX|_],LL),
length(LX,MaxLen).
findmax(V,P,Max) :-
findall(V,P,L),
max(L,Max).
max([N],N) :- !.
max([N|R],Max) :-
max(R,Max2),
max3(N,Max2,Max).
max3(N,Max2,N) :- N > Max2,!.
max3(N,Max2,Max2).
To have the length of longest list:
%sample: longest([[2,1,3],[7,5],[1,8,2,3,1],[2,7,1,4]],L,LEN).
longest([L], L, _) :-
!.
longest([H|T], H, _) :-
length(H, N),
longest(T, X, N),
length(X, M),
N > M,
!.
longest([_|T], X, LEN) :-
length(X, LEN),
longest(T, X, LEN),
!.