Related
I'm trying to count the numer of inversions in a list. A predicate inversion(+L,-N) unifies N to the number of inversions in that list. A inversion is defined as X > Y and X appears before Y in the list (unless X or Y is 0). For example:
?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.
For what I'm using this for, the list will always have exacly 9 elements, and always containing the numbers 0-8 uniquely.
I'm quite new to Prolog and I'm trying to do this as concise and as elegant as possible; It seems like DCG will probably help a lot. I read into the official definition and some tutorial sites, but still don't quit understand what it is. Any help would be greatly appreciated.
Here is another solution that doesn't leave choice points using if_/3:
inversions([],0).
inversions([H|T], N):-
if_( H = 0,
inversions(T,N),
( find_inv(T,H,N1),inversions(T, N2), N #= N1+N2 )
).
find_inv([],_,0).
find_inv([H1|T],H,N1):-
if_( H1=0,
find_inv(T,H,N1),
if_( H#>H1,
(find_inv(T,H,N2),N1 #= N2+1),
find_inv(T,H,N1)
)
).
#>(X, Y, T) :-
( integer(X),
integer(Y)
-> ( X > Y
-> T = true
; T = false
)
; X #> Y,
T = true
; X #=< Y,
T = false
).
I'm not so sure a DCG would be helpful here. Although we're processing a sequence, there's a lot of examination of the entire list at each point when looking at each element.
Here's a CLPFD approach which implements the "naive" algorithm for inversions, so it's transparent and simple, but not as efficient as it could be (it's O(n^2)). There's a more efficient algorithm (O(n log n)) involving a divide and conquer approach, which I show further below.
:- use_module(library(clpfd)).
inversions(L, C) :-
L ins 0..9,
all_distinct(L),
count_inv(L, C).
% Count inversions
count_inv([], 0).
count_inv([X|T], C) :-
count_inv(X, T, C1), % Count inversions for current element
C #= C1 + C2, % Add inversion count for the rest of the list
count_inv(T, C2). % Count inversions for the rest of the list
count_inv(_, [], 0).
count_inv(X, [Y|T], C) :-
( X #> Y, X #> 0, Y #> 0
-> C #= C1 + 1, % Valid inversion, count it
count_inv(X, T, C1)
; count_inv(X, T, C)
).
?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0 ;
false.
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3 ;
false.
?- inversions([0,2,X],1).
X = 1 ;
false.
It does leave a choice point, as you can see, which I haven't sorted out yet.
Here's the O(n log n) solution, which is using the sort/merge algorithm.
inversion([], [], 0).
inversion([X], [X], 0).
inversion([HU1, HU2|U], [HS1, HS2|S], C) :- % Ensure list args have at least 2 elements
split([HU1, HU2|U], L, R),
inversion(L, SL, C1),
inversion(R, SR, C2),
merge(SL, SR, [HS1, HS2|S], C3),
C #= C1 + C2 + C3.
% Split list into left and right halves
split(List, Left, Right) :-
split(List, List, Left, Right).
split(Es, [], [], Es).
split(Es, [_], [], Es).
split([E|Es], [_,_|T], [E|Ls], Right) :-
split(Es, T, Ls, Right).
% merge( LS, RS, M )
merge([], RS, RS, 0).
merge(LS, [], LS, 0).
merge([L|LS], [R|RS], [L|T], C) :-
L #=< R,
merge(LS, [R|RS], T, C).
merge([L|LS], [R|RS], [R|T], C) :-
L #> R, R #> 0 #<==> D, C #= C1+D,
merge([L|LS], RS, T, C1).
You can ignore the second argument, which is the sorted list (just a side effect if all you want is the count of inversions).
Here is another possibility to define the relation. First, #</3 and #\=/3 can be defined like so:
:- use_module(library(clpfd)).
bool_t(1,true).
bool_t(0,false).
#<(X,Y,Truth) :- X #< Y #<==> B, bool_t(B,Truth).
#\=(X,Y,Truth) :- X #\= Y #<==> B, bool_t(B,Truth).
Based on that, if_/3 and (',')/3 a predicate inv_t/3 can be defined, that yields true in the case of an inversion and false otherwise, according to the definition given by the OP:
inv_t(X,Y,T) :-
if_(((Y#<X,Y#\=0),X#\=0),T=true,T=false).
And subsequently the actual relation can be described like so:
list_inversions(L,I) :-
list_inversions_(L,I,0).
list_inversions_([],I,I).
list_inversions_([X|Xs],I,Acc0) :-
list_x_invs_(Xs,X,I0,0),
Acc1 #= Acc0+I0,
list_inversions_(Xs,I,Acc1).
list_x_invs_([],_X,I,I).
list_x_invs_([Y|Ys],X,I,Acc0) :-
if_(inv_t(X,Y),Acc1#=Acc0+1,Acc1#=Acc0),
list_x_invs_(Ys,X,I,Acc1).
Thus the example queries given by the OP succeed deterministically:
?- list_inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.
?- list_inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.
Such application-specific constraints can often be built using reified constraints (constraints whose truth value is reflected into a 0/1 variable). This leads to a relatively natural formulation, where B is 1 iff the condition you want to count is satisfied:
:- lib(ic).
inversions(Xs, N) :-
( fromto(Xs, [X|Ys], Ys, [_]), foreach(NX,NXs) do
( foreach(Y,Ys), param(X), foreach(B,Bs) do
B #= (X#\=0 and Y#\=0 and X#>Y)
),
NX #= sum(Bs) % number of Ys that are smaller than X
),
N #= sum(NXs).
This code is for ECLiPSe.
Using clpfd et automaton/8 we can write
:- use_module(library(clpfd)).
inversions(Vs, N) :-
Vs ins 0..sup,
variables_signature(Vs, Sigs),
automaton(Sigs, _, Sigs,
[source(s),sink(i),sink(s)],
[arc(s,0,s), arc(s,1,s,[C+1]), arc(s,1,i,[C+1]),
arc(i,0,i)],
[C], [0], [N]),
labeling([ff],Vs).
variables_signature([], []).
variables_signature([V|Vs], Sigs) :-
variables_signature_(Vs, V, Sigs1),
variables_signature(Vs, Sigs2),
append(Sigs1, Sigs2, Sigs).
variables_signature_([], _, []).
variables_signature_([0|Vs], Prev, Sigs) :-
variables_signature_(Vs,Prev,Sigs).
variables_signature_([V|Vs], Prev, [S|Sigs]) :-
V #\= 0,
% Prev #=< V #<==> S #= 0,
% modified after **false** remark
Prev #> V #<==> S,
variables_signature_(Vs,Prev,Sigs).
examples :
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3 ;
false.
?- inversions([1,2,3,0,4,5,6,7,8],N).
N = 0 ;
false.
?- inversions([0,2,X],1).
X = 1.
in SWI-Prolog, with libraries aggregate and lists:
inversions(L,N) :-
aggregate_all(count, (nth1(P,L,X),nth1(Q,L,Y),X\=0,Y\=0,X>Y,P<Q), N).
both libraries are autoloaded, no need to explicitly include them.
If you want something more general, you can see the example in library(clpfd), under the automaton section, for some useful ideas. But I would try to rewrite your specification in simpler terms, using element/3 instead of nth1/3.
edit
after #false comment, I tried some variation on disequality operators, but none I've tried have been able to solve the problematic query. Then I tried again with the original idea, to put to good use element/3. Here is the result:
:- use_module(library(clpfd)).
inversions(L) :-
L ins 0..8,
element(P,L,X),
element(Q,L,Y),
X #\= 0, Y #\= 0, X #> Y, P #< Q,
label([P,Q]).
inversions(L,N) :-
aggregate(count, inversions(L), N) ; N = 0.
The last line label([P,Q]) it's key to proper reification: now we can determine the X value.
?- inversions([0,2,X],1).
X = 1.
I am new to prolog, and I think I have an really easy problem to solve, but i cant find sollution anywhere.
So i have a list of lists and I need to find all elements in it with esteblished length.
This is what i came to, but it is not working.
averegelist_([[]],[[]]).
averegelist_([Wo|List], Averege, NewL):-
length(Wo,N), N+1=:=Averege, averegelist_(List, NewL).
averegelist([Word|List1],Av, [Word|List2]):-
length(Word,N), N+1=\=Av, averegelist_(List1, Av, List2).
What i expected is somethig like this:
?- averegelist([['a','b','c'],['f','g'],['h','m']],2, X)).
X = ['f','g'].
X = ['h','m'].
False
Can somebody help me, please?
Edit:
So, I did it! For anyone interested in this topik this is what my code looks like:
split_on_delimiter(L, D, S) :-
split_on_delimiter_(L, D, R),
findall(X, (member(X, R), length(X,Length), Length > 0), S).
split_on_delimiter_([], _, [[]]).
split_on_delimiter_([D|T], D, [[]|T2]) :-
split_on_delimiter_(T, D, T2).
split_on_delimiter_([H|T], D, [[H|T2]|T3]) :-
dif(H, D),
split_on_delimiter_(T, D, [T2|T3]).
my_length([],0).
my_length([_|L],N) :- my_length(L,N1), N is N1 + 1.
my_length_lol([], 0).
my_length_lol([H|L],N) :- my_length(H,Add), my_length_lol(L,N1), N is N1 + Add.
countAver(L,Av):- length(L,ListN), my_length_lol(L,AllN), Av is div(AllN,ListN).
test_condition(X, Con):- length(X, N), N =:= Con.
select_element_on_condition([X|Xs], X, Con) :-
test_condition(X, Con).
select_element_on_condition([_|Xs], X, Con) :-
select_element_on_condition(Xs, X, Con).
findAvWord(L, X):- split_on_delimiter(L,' ', Words), countAver(Words, AvWordLength),
write(AvWordLength), select_element_on_condition(Words, X, AvWordLength).
findAvWord(L, X) L - is a list of simbols, X - is a word of averege Length in this list.
split_on_delimiter(L,D,S) S is - list of lists from L, based on delimiter(' ' in my case)
I think you're making this problem harder than it really is. Here's a simple predicate framework that succeeds for list elements that meet a specific criteria. You should be able to adapt this to your problem.
select_element_on_condition([X|Xs], X) :-
test_condition(X).
select_element_on_condition([_|Xs], X) :-
select_element_on_condition(Xs, X).
In your case, your elements are lists, and the test condition is for the length.
just to show how to solve such problem using modern libraries like apply and yall - where available -
averegelist(Lists, Length, ListsOfLength) :-
include({Length}/[List]>>length(List,Length), Lists, ListsOfLength).
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).
How can I replace a list with another list that contain the variable to be replaced. for example
rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p]
the x to z and z doesn't change after it has been replaced.
so far I did only the one without the list
rep([], _, []).
rep(L1, H1=H2, L2) :-
rep(L1, H1, H2, L2).
rep([],_,_,[]).
rep([H|T], X1, X2, [X2|L]) :-
H=X1,
rep(T,X1,X2,L),
!.
rep([H|T],X1,X2,[H|L]) :-
rep(T,X1,X2,L).
If you use SWI-Prolog, with module lambda.pl found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl you can write :
:- use_module(library(lambda)).
rep(L, Rep, New_L) :-
maplist(\X^Y^(member(X=Z, Rep)
-> Y = Z
; Y = X), L, New_L).
You should attempt to keep the code simpler than possible:
rep([], _, []).
rep([X|Xs], Vs, [Y|Ys]) :-
( memberchk(X=V, Vs) -> Y = V ; Y = X ),
rep(Xs, Vs, Ys).
Of course, note the idiomatic way (thru memberchk/2) to check for a variable value.
Still yet a more idiomatic way to do: transforming lists it's a basic building block in several languages, and Prolog is no exception:
rep(Xs, Vs, Ys) :- maplist(repv(Vs), Xs, Ys).
repv(Vs, X, Y) :- memberchk(X=V, Vs) -> Y = V ; Y = X .
Here's how you could proceed using if_/3 and (=)/3.
First, we try to find a single Key in a list of pairs K-V.
An extra argument reifies search success.
pairs_key_firstvalue_t([] ,_ ,_ ,false).
pairs_key_firstvalue_t([K-V|KVs],Key,Value,Truth) :-
if_(K=Key,
(V=Value, Truth=true),
pairs_key_firstvalue_t(KVs,Key,Value,Truth)).
Next, we need to handle "not found" cases:
assoc_key_mapped(Assoc,Key,Value) :-
if_(pairs_key_firstvalue_t(Assoc,Key,Value),
true,
Key=Value).
Last, we put it all together using the meta-predicate maplist/3:
?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p]. % OK, succeeds deterministically
Let's improve this answer by moving the "recursive part" into meta-predicate find_first_in_t/4:
:- meta_predicate find_first_in_t(2,?,?,?).
find_first_in_t(P_2,X,Xs,Truth) :-
list_first_suchthat_t(Xs,X,P_2,Truth).
list_first_suchthat_t([] ,_, _ ,false).
list_first_suchthat_t([E|Es],X,P_2,Truth) :-
if_(call(P_2,E),
(E=X,Truth=true),
list_first_suchthat_t(Es,X,P_2,Truth)).
To fill in the "missing bits and pieces", we define key_pair_t/3:
key_pair_t(Key,K-_,Truth) :-
=(Key,K,Truth).
Based on find_first_in_t/4 and key_pair_t/3, we can write assoc_key_mapped/3 like this:
assoc_key_mapped(Assoc,Key,Value) :-
if_(find_first_in_t(key_pair_t(Key),_-Value,Assoc),
true,
Key=Value).
So, does the OP's use-case still work?
?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p]. % OK. same result as before
Building on find_first_in_t/4
memberd_t(X,Xs,Truth) :- % memberd_t/3
find_first_in_t(=(X),_,Xs,Truth).
:- meta_predicate exists_in_t(2,?,?). % exists_in_t/3
exists_in_t(P_2,Xs,Truth) :-
find_first_in_t(P_2,_,Xs,Truth).
I find your code rather confused. For one thing, you have rep/3 and rep/4, but none of them have a list in the second position where you're passing the list of variable bindings. H1=H2 cannot possibly match a list, and that's the only rep/3 clause that examines the second argument. If this is a class assignment, it looks like you're a little bit behind and I'd suggest you spend some time on the previous material.
The solution is simpler than you'd think:
rep([], _, []).
rep([X|Xs], Vars, [Y|Rest]) :- member(X=Y, Vars), rep(Xs, Vars, Rest).
rep([X|Xs], Vars, [X|Rest]) :- \+ member(X=_, Vars), rep(Xs, Vars, Rest).
We're using member/2 to find a "variable binding" in the list (in quotes because these are atoms and not true Prolog variables). If it's in the list, Y is the replacement, otherwise we keep using X. And you see this has the desired effect:
?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p] ;
false.
This could be made somewhat more efficient using "or" directly (and save us a choice point):
rep([], _, []).
rep([X|Xs], Vars, [Y|Ys]) :-
(member(X=Y, Vars), ! ; X=Y),
rep(Xs, Vars, Ys).
See:
?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p].
I have defined a goal lowerpartition/3 as follows:
lowerpartition(X,P,Z) :- var(Z),!,lowerpartition(X,P,[]).
lowerpartition([],_,_).
lowerpartition([X|Xs],P,Z) :- X=<P, lowerpartition(Xs,P,[X|Z]).
lowerpartition([X|Xs],P,Z) :- X>P, lowerpartition(Xs,P,Z).
when I call
lowerpartition([1,2,3,4,5],3,X).
I expect X to be bound to the list [3,2,1], but Prolog just returns false. What am I doing incorrectly?
It seems that you are mixing an accumulator-based approach with a stack based approach.
Your first clause:
lowerpartition(X,P,Z) :- var(Z),!,lowerpartition(X,P,[]).
will leave Z uninstantiated, it is not used after checking that it is a variable therfore it won't be unified...
Try this:
lowerpartition([], _, []).
lowerpartition([X|Xs], P, [X|Zs]):-
X =< P, lowerpartition(Xs, P, Zs).
lowerpartition([X|Xs], P, Zs):-
X > P, lowerpartition(Xs, P, Zs).
Because you use a predicate that prolog cant unify in the first clause.
lowerpartition(X,P,Z) :- var(Z),
!,
lowerpartition(X,P,[]). % here is what prolog cant unify
A little modification to the code :
lowerpartition(X,P,Z) :- var(Z),lowerpartition_1(X,P,Z),!. % note the position of cut aswell
lowerpartition_1([],_,[]).
lowerpartition_1([X|Xs],P,[X|Z]) :- X=<P, lowerpartition_1(Xs,P,Z).
lowerpartition_1([X|Xs],P,Z) :- X>P, lowerpartition_1(Xs,P,Z).
Hope this helps.
Here a DCG based solution: my simple minded test return the same results as gusbro solution.
lowerpartition(P), [X] --> [X], {X=<P}, lowerpartition(P), !.
lowerpartition(P) --> [X], {X>P}, lowerpartition(P).
lowerpartition(_) --> [].
here is how to call it:
?- phrase(lowerpartition(3), [1,2,3,4,5,3,2,6,7], X).
X = [1, 2, 3, 3, 2].
but if you are using a Prolog with lìbrary(apply), then
lowerpartition(Xs, P, Rs) :- exclude(compare(<, P), Xs, Rs).
returns the same result as above