I have an optimisation problem, where I want to minimse the length of a list which I have yet to construct. Language here is Prolog, using swipl's clpfd library.
Something along the lines of pred(L), length(L,N), labeling([min(N)],[....]).
Problem is: length/2 already sets the length, even if L is a variable, so this ain't CLP optimisation after that.
So, can I somehow constrain the length of L to be N without instantiating N? Perhaps using reification if I know an upper bound for N (which I do) - but that does sound awfully complicated? TBH I have similar issues stopping with my pred/1 thing to commit to a particular list length, but I was just primarily curious about that length thing.
Can delay using when:
list_min_max_len(MinLen, MaxLen, Lst) :-
when(nonvar(MinLen), (
MinLen #>= 0,
ensure_min_len(MinLen, Lst)
)),
when((nonvar(MinLen), nonvar(MaxLen)), (
MaxLen #>= MinLen
)),
when(nonvar(MaxLen),
max_len_freeze(Lst, 0, MaxLen)
).
max_len_freeze([], Upto, MaxLen) :-
Upto == MaxLen,
% At max len, so avoid [H|T]
!.
max_len_freeze([], Upto, MaxLen) :-
Upto #< MaxLen.
max_len_freeze([_|T], Upto, MaxLen) :-
Upto1 is Upto + 1,
compare(Comp, MaxLen, Upto1),
max_len_freeze_next_(Comp, T, Upto1, MaxLen).
max_len_freeze_next_(=, [], Upto, MaxLen) :-
max_len_freeze([], Upto, MaxLen).
max_len_freeze_next_(>, T, Upto, MaxLen) :-
when(nonvar(T), max_len_freeze(T, Upto, MaxLen)).
ensure_min_len(MinLen, Lst) :-
compare(Comp, MinLen, 0),
ensure_min_len_(Comp, Lst, MinLen).
ensure_min_len_(=, _, 0).
ensure_min_len_(>, [_|T], MinLen) :-
MinLen0 is MinLen - 1,
compare(Comp, MinLen0, 0),
ensure_min_len_(Comp, T, MinLen0).
Results in swi-prolog:
?- list_min_max_len(Min, Max, L), L = [a,b,c|T], Max = 3, Min = 3.
L = [a, b, c],
Min = Max, Max = 3,
T = [].
?- list_min_max_len(Min, Max, L), L = [a,b,c|T], Min = 5.
L = [a, b, c, _A, _B|_C],
Min = 5,
T = [_A, _B|_C],
when(nonvar(Max), max_len_freeze([a, b, c, _A, _B|_C], 0, Max)),
when(nonvar(Max), Max#>=5).
% Prevents length/2 from going to infinity, if MaxLen is specified first
?- list_min_max_len(Min, Max, L), L = [a,b,c|T], Min = 2, Max = 5, length(L, Len).
L = [a, b, c],
Min = 2,
Max = 5,
T = [],
Len = 3 ;
L = [a, b, c, _A],
Min = 2,
Max = 5,
T = [_A],
Len = 4 ;
L = [a, b, c, _A, _B],
Min = 2,
Max = Len, Len = 5,
T = [_A, _B].
% Beware - can't magically rein in length/2
?- list_min_max_len(Min, Max, L), Min = 2, L = [a,b,c|T], length(L, Len), Max = 3.
L = [a, b, c],
Min = 2,
Max = Len, Len = 3,
T = [] ;
<length/2 goes to infinity>
Related
I'm new to Prolog and I have this code. I would like it to split a list into two lists or sublists where the first sublist/ list is of a predefined length and the other one contains the rest of the elements. Here's the code.
`
list_length([],0).
list_length([_|T],N):- list_length(T, N1), N is N1 + 1.
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
length(B, N).
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
N1 is N + 1,
length(B, N1).
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
N1 is N - 1,
length(B, N1).
``
When I run my above code, it returns an error saying:
ERROR: Unknown procedure: (div)/4
ERROR: However, there are definitions for:
ERROR: (div)/3
false.
I would like the input to be this:
`?- div([44,55,23,86,49,94,30,77], L1, L2, 6).
L1 = [44,55,23,86,49,94]
L2 = [30,77]
Help me understand what I am doing wrong.
Help me understand what I am doing wrong.
You should be using length/2 and append/3, one after the other, like this:
div(L, A, B, N) :-
append(A, B, L),
length(A, N).
This is all.
Do not define your own length/2.
But you have not shown how you compile and evaluate your code. For example, I get:
?- [user].
|: div(L, A, B, N) :- append(A, B, L), length(A, N).
|: ^D% user://1 compiled 0.01 sec, 1 clauses
true.
?- div([a,b,c,d], A, B, 2).
A = [a, b],
B = [c, d] ;
false.
?- div([a,b,c,d], [X,Y], B, N).
X = a,
Y = b,
B = [c, d],
N = 2.
?- div([a,b,c,d], A, [X,Y,Z], N).
A = [a],
X = b,
Y = c,
Z = d,
N = 1 ;
false.
?- div([a,b], A, B, N).
A = [],
B = [a, b],
N = 0 ;
A = [a],
B = [b],
N = 1 ;
A = [a, b],
B = [],
N = 2 ;
false.
?- div(L, A, B, N).
L = B,
A = [],
N = 0 ;
L = [_A|B],
A = [_A],
N = 1 ;
L = [_A, _B|B],
A = [_A, _B],
N = 2 .
Since I made that mistake already, it is worth asking: Can you switch the order of append and length in the definition? What happens if you do?
I have to write a predicate: double(X,Y) to be true when Y is the list consisting of each element of X
repeated twice (e.g. double([a,b],[a,a,b,b]) is true).
I ended with sth like this:
double([],[]).
double([T],List) :- double([H|T],List).
double([H|T],List) :- count(H, List, 2).
Its working fine for lists like [a,a,b] but it shouldnt... please help.
And i need help with another predicate: repeat(X,Y,N) to be true when Y is the list consisting of each element of X
repeated N times (e.g. repeat([a,b], [a,a,a,b,b,b],3) is true).
double([],[]).
double([I|R],[I,I|RD]) :-
double(R,RD).
Here's how you could realize that "repeat" predicate you suggested in the question:
:- use_module(library(clpfd)).
Based on if_/3 and (=)/3 we define:
each_n_reps([E|Es], N) :-
aux_n_reps(Es, E, 1, N).
aux_n_reps([], _, N, N). % internal auxiliary predicate
aux_n_reps([E|Es], E0, N0, N) :-
if_(E0 = E,
( N0 #< N, N1 #= N0+1 ), % continue current run
( N0 #= N, N1 #= 1 )), % start new run
aux_n_reps(Es, E, N1, N).
Sample queries1 using SICStus Prolog 4.3.2:
?- each_n_reps(Xs, 3).
Xs = [_A,_A,_A]
; Xs = [_A,_A,_A,_B,_B,_B] , dif(_A,_B)
; Xs = [_A,_A,_A,_B,_B,_B,_C,_C,_C], dif(_A,_B), dif(_B,_C)
...
How about fair enumeration?
?- length(Xs, _), each_n_reps(Xs, N).
N = 1, Xs = [_A]
; N = 2, Xs = [_A,_A]
; N = 1, Xs = [_A,_B] , dif(_A,_B)
; N = 3, Xs = [_A,_A,_A]
; N = 1, Xs = [_A,_B,_C] , dif(_A,_B), dif(_B,_C)
; N = 4, Xs = [_A,_A,_A,_A]
; N = 2, Xs = [_A,_A,_B,_B], dif(_A,_B)
; N = 1, Xs = [_A,_B,_C,_D], dif(_A,_B), dif(_B,_C), dif(_C,_D)
...
How can [A,B,C,D,E,F] be split into runs of equal length?
?- each_n_reps([A,B,C,D,E,F], N).
N = 6, A=B , B=C , C=D , D=E , E=F
; N = 3, A=B , B=C , dif(C,D), D=E , E=F
; N = 2, A=B , dif(B,C), C=D , dif(D,E), E=F
; N = 1, dif(A,B), dif(B,C), dif(C,D), dif(D,E), dif(E,F).
Footnote 1: Answers were reformatted to improve readability.
Ok for repeat/3 i have sth like this:
repeat1([],[],0).
repeat1([A|B],[X|T],Y):- repeat1(B,T,Z), Y is 1+Z.
repeat1([A1|B],[X1|T], Z) :- A1\=A, X1\=X, repeat1(B,T,Z).
I am fresh in Prolog. And I am trying to write a predicate that finds the Max value and its index of a list of integers. i.e max_list([2,3,4], MAX, INDEX) will yield MAX=4, INDEX=2
Thank you for reply~ My apologize! This is the first time I ask questions in stackoverflow. I could write a predicate to find the maximum or a minimum of a list, but I don't know how to get the exact position the value in the list. I am just trying to comprehend the answers.
Using clpfd ...
:- use_module(library(clpfd)).
..., meta-predicate maplist/2, and nth0/3 we define:
zs_maximum_at(Zs,Max,Pos) :-
maplist(#>=(Max),Zs),
nth0(Pos,Zs,Max).
Here's the query the OP gave:
?- zs_maximum_at([2,3,4],M,I).
I = 2, M = 4.
OK! ... how about the most general query?
?- zs_maximum_at(Zs,M,I).
Zs = [M], I = 0, M in inf..sup
; Zs = [ M,_B], I = 0, M #>= _B
; Zs = [_A, M], I = 1, M #>= _A
; Zs = [ M,_B,_C], I = 0, M #>= _B, M #>= _C
; Zs = [_A, M,_C], I = 1, M #>= _A, M #>= _C
; Zs = [_A,_B, M], I = 2, M #>= _A, M #>= _B
; Zs = [ M,_B,_C,_D], I = 0, M #>= _B, M #>= _C, M #>= _D
; Zs = [_A, M,_C,_D], I = 1, M #>= _A, M #>= _C, M #>= _D
...
Edit: What about arithmetic expressions?
We can allow the use of arithmetic expressions by adding an additional goal (#=)/2:
zs_maximum_at(Zs,Expr,Pos) :-
maplist(#>=(Max),Zs),
nth0(Pos,Zs,Expr),
Expr #= Max.
Now we can run queries like the following one—but lose monotonicity (cf. this clpfd manual)!
?- zs_maximum_at([0+1,1+1,2-0,3-1,1+0],M,I).
I = 1, M = 1+1
; I = 2, M = 2-0
; I = 3, M = 3-1
; false.
To disable arithmetic expressions we can use length/2 in combination with ins/2:
zs_maximum_at(Zs,Max,Pos) :-
length(Zs,_),
Zs ins inf..sup,
maplist(#>=(Max),Zs),
nth0(Pos,Zs,Max).
Running above query again, we now get:
?- zs_maximum_at([0+1,1+1,2-0,3-1,1+0],M,I).
ERROR: Type error: `integer' expected, found `0+1' (a compound)
Note that the issue (of allowing arithmetic expressions or not) is not limited to clpfd.It is also present when using plain-old Prolog arithmetic predicates like is/2 and friends.
a variation on joel76 answer:
max_list(L, M, I) :- nth0(I, L, M), \+ (member(E, L), E > M).
I'm no Prolog expert myself so this is probably not the most beautiful solution, but this predicate should do what you want:
max_list([X|Xs],Max,Index):-
max_list(Xs,X,0,0,Max,Index).
max_list([],OldMax,OldIndex,_, OldMax, OldIndex).
max_list([X|Xs],OldMax,_,CurrentIndex, Max, Index):-
X > OldMax,
NewCurrentIndex is CurrentIndex + 1,
NewIndex is NewCurrentIndex,
max_list(Xs, X, NewIndex, NewCurrentIndex, Max, Index).
max_list([X|Xs],OldMax,OldIndex,CurrentIndex, Max, Index):-
X =< OldMax,
NewCurrentIndex is CurrentIndex + 1,
max_list(Xs, OldMax, OldIndex, NewCurrentIndex, Max, Index).
Another approach, not very efficient but more "prologish" is to say :
What is the max of a list ? it's a member of the list, and no other member of this list is greater than the max !
So :
max_list(Lst, Max, Ind) :-
member(Max, Lst),
\+((member(N, Lst), N > Max)),
% Now, with SWI-Prolog, (may be with other Prolog)
% nth0/3 gives you the index of an element in a list
nth0(Ind, Lst, Max).
I would like to delete the last n elements of a list in Prolog and put it in another list say L2. If I knew the exact number of elements to delete say 3, here is the code. But I am stuck with the variable n case. Btw I would like to return an empty string if the length of the list is shorter than n. Thank you.
without_last_three([], []).
without_last_three([_], []).
without_last_three([_,_], []).
without_last_three([_,_,_], []).
without_last_three([Head|Tail], [Head|NTail]):-
without_last_three(Tail, NTail).
without_last_n(Old, N, New) :-
length(Tail, N),
append(New, Tail, Old).
Test run:
?- without_last_n([a, b, c, d, e, f], 4, New).
New = [a, b]
?- without_last_n([a, b, c, d, e, f], 777, New).
false.
?- without_last_n([a, b, c, d, e, f], 0, New).
New = [a, b, c, d, e, f]
Update. To succeed with an [] when N is bigger than the length of the list, second clause can be added:
without_last_n(Old, N, []) :-
length(Old, L),
N > L.
Here is a general case:
without_last_n(L, N, []) :-
nonvar(L), nonvar(N),
length(L, M),
N > M.
without_last_n(L, N, R) :-
without_last_n_(L, N, R).
without_last_n_(L, N, []) :-
length(L, N).
without_last_n_([H|T], N, [H|T1]) :-
without_last_n_(T, N, T1).
This satisfies the given requirements, and works with a variety of variable instantiation scenarios. What complicates the solution a bit is the requirement that without_last_n(L, N, []). must succeed if N is greater than the length of L. If this was not a requirement, then the much simpler without_last_n_/3 would suffice as a solution to the problem.
Testing...
| ?- without_last_n([1,2,3,4], 3, R).
R = [1] ? ;
no
| ?- without_last_n([1,2,3,4], N, R).
N = 4
R = [] ? ;
N = 3
R = [1] ? ;
N = 2
R = [1,2] ? ;
N = 1
R = [1,2,3] ? ;
N = 0
R = [1,2,3,4]
(1 ms) yes
| ?- without_last_n([1,2,3,4], N, [1,2]).
N = 2 ? ;
no
| ?- without_last_n(L, 3, [1,2]).
L = [1,2,_,_,_] ? ;
no
| ?- without_last_n(L, 2, R).
L = [_,_]
R = [] ? ;
L = [A,_,_]
R = [A] ? ;
L = [A,B,_,_]
R = [A,B] ? ;
L = [A,B,C,_,_]
R = [A,B,C] ?
...
| ?- without_last_n(L, N, [1,2]).
L = [1,2]
N = 0 ? ;
L = [1,2,_]
N = 1 ? ;
L = [1,2,_,_]
N = 2 ? ;
...
| ?- without_last_n(L, N, R).
L = []
N = 0
R = [] ? ;
L = [_]
N = 1
R = [] ? ;
L = [_,_]
N = 2
R = [] ? ;
L = [_,_,_]
N = 3
R = [] ? ;
...
| ?-
A possible flaw here is that without_last_n([1,2,3,4], N, R). perhaps could generate solutions ad infinitum of N = 5, R = [], N = 6, R = [], etc. But it doesn't. Left as an exercise for the reader. :)
i m new in prolog that s why may be the question is easy for you but i couldnt find the answer. Can someone please help me.
I just want
a count function s.t
count([c,c,a,a,b,b,d,a,c,b,d,d,a], O).
it will returns the number of occurences of the list members.
O = [[a, 4], [b, 3], [c, 3], [d, 3]]
The following is based on my previous answer to "Remove duplicates in list (Prolog)" and on this previous answer to the question "Prolog union for A U B U C".
list_item_subtracted_count0_count/5 is derived from list_item_subtracted/3.
list_counts/2 is derived from list_setB/2, which were both defined here.
list_item_subtracted_count0_count([], _, [], N,N).
list_item_subtracted_count0_count([A|As], E, Bs1, N0,N) :-
if_(A = E,
( Bs1 = Bs , N1 is N0+1 ),
( Bs1 = [A|Bs], N1 = N0 )),
list_item_subtracted_count0_count(As, E, Bs, N1,N).
list_counts([], []).
list_counts([X|Xs], [X-N|Ys]) :-
list_item_subtracted_count0_count(Xs, X, Xs0, 1,N),
list_counts(Xs0, Ys).
Here's the query the OP gave:
?- list_counts([c,c,a,a,b,b,d,a,c,b,d,d,a], Xss).
Xss = [c-3,a-4,b-3,d-3]. % succeeds deterministically
Note the order of pairs X-N in Counts corresponds to the first occurrence of X in Xs:
?- list_counts([a,b,c,d], Xss).
Xss = [a-1,b-1,c-1,d-1].
?- list_counts([d,c,b,a], Xss).
Xss = [d-1,c-1,b-1,a-1].
Last, let's consider all possible lists Es—enumerated fairly with ascending lengths:
?- length(Es, N), list_counts(Es, Xss).
N = 0, Es = [], Xss = []
; N = 1, Es = [A], Xss = [A-1]
; N = 2, Es = [A,A], Xss = [A-2]
; N = 2, Es = [A,B], Xss = [A-1,B-1], dif(B,A)
; N = 3, Es = [A,A,A], Xss = [A-3]
; N = 3, Es = [A,A,B], Xss = [A-2,B-1], dif(B,A)
; N = 3, Es = [A,B,A], Xss = [A-2,B-1], dif(B,A)
; N = 3, Es = [B,A,A], Xss = [B-1,A-2], dif(A,B), dif(A,B)
; N = 3, Es = [A,B,C], Xss = [A-1,B-1,C-1], dif(C,A), dif(C,B), dif(B,A)
...
co(X,L) :- co(X,[],L).
co([],A,A).
co([X|Xs], A, L) :- p(X-Z,A,R), !, Z1 is Z+1, co(Xs, [X-Z1|R], L).
co([X|Xs], A, L) :- co(Xs, [X-1|A], L).
p(X-Y,[X-Y|R],R):- !.
p(X,[H|Y], [H|Z]) :- p(X,Y,Z).
I did not use very meaningful names on purpose. Try to understand what each one of the predicates does.