Related
Given the frequent pure definition of same_length/2 as
same_length([],[]).
same_length([_|As], [_|Bs]) :-
same_length(As, Bs).
?- same_length(L, [_|L]).
loops.
Is there a pure definition that does not loop for such cases? Something in analogy to the pure (but less efficient) version of append/3 called append2u/3.
I know how to catch such cases manually with var/1 and the like, but ideally a version that is just as pure as the original definition would be desirable. Or at least it should be simple.
What I have tried is the definition above.
One clarification seems to be in order:
Note that there are certain queries that inherently must not terminate. Think of:
?- same_length(Ls, Ks).
Ls = [], Ks = []
; Ls = [_A], Ks = [_B]
; Ls = [_A,_B], Ks = [_C,_D]
; Ls = [_A,_B,_C], Ks = [_D,_E,_F]
; Ls = [_A,_B,_C,_D], Ks = [_E,_F,_G,_H]
; ... .
There is no other way to enumerate all solutions using the language of syntactic answer substitutions.
But still an implementation may terminate for the queries given.
This answer aims at minimising runtime costs.
It is built on '$skip_max_list'/4 and runs on Scryer Prolog.
First up, some auxiliary code:
:- use_module(library(lists)).
'$skip_list'(N,Xs0,Xs) :-
'$skip_max_list'(N,_,Xs0,Xs).
is_list([]).
is_list([_|Xs]) :-
is_list(Xs).
sam_length_([],[]).
sam_length_([_|Xs],[_|Ys]) :-
sam_length_(Xs,Ys).
Now the main dish:
sam_length(Ls1,Ls2) :-
'$skip_list'(L1,Ls1,Rs1),
( Rs1 == []
-> length(Ls2,L1)
; var(Rs1),
'$skip_max_list'(L2,L1,Ls2,Rs2),
( L2 < L1
-> var(Rs2),
Rs1 \== Rs2,
'$skip_max_list'(_,L2,Ls1,Ps1),
sam_length_(Ps1,Rs2)
; '$skip_list'(N2,Rs2,Ts2),
( Ts2 == []
-> M1 is N2-L1,
length(Rs1,M1)
; var(Ts2),
( N2 > 0
-> Ts2 \== Rs1,
sam_length_(Rs2,Rs1) % switch argument order
; Rs1 == Rs2
-> is_list(Rs1) % simpler enumeration
; sam_length_(Rs1,Rs2)
)
)
)
).
Sample queries:
?- sam_length(L,[_|L]).
false.
?- sam_length([_],L).
L = [_A].
?- sam_length(L,M).
L = [], M = []
; L = [_A], M = [_B]
; ... .
A solution using '$skip_max_list'/4:
% Clause for `?- L = [a|L], same_length(L, _)`.
same_length(As, Bs) :-
(Cs = As ; Cs = Bs),
'$skip_max_list'(_, _, Cs, Cs0),
subsumes_term([_|_], Cs0), !,
false.
% Clause for `?- same_length(L, [_|L])`.
same_length(As, Bs) :-
As \== Bs,
'$skip_max_list'(S, _, As, As0),
'$skip_max_list'(T, _, Bs, Bs0),
As0 == Bs0,
S \== T, !,
false.
same_length(As, Bs) :-
same_length_(As, Bs).
same_length_([], []).
same_length_([_|As], [_|Bs]) :-
same_length_(As, Bs).
Queries:
?- L = [a|L], same_length(L, _).
false.
?- same_length(L, [_|L]).
false.
?- same_length([_], L).
L = [_A].
?- same_length(L, M).
L = [], M = []
; L = [_A], M = [_B]
; ... .
UPDATED SOLUTION
Here is my solution:
same_length(A, A).
same_length([_|A], [_|B]) :- same_length(A, B).
?- same_length(L, [_|L]).
L = [_1696|L]
I am not sure if it has all the properties you're looking for. For example if you call
? - same_length(L, [1,2,3]).
then it lists many answers, e.g. L = [_X, 2, 3], rather than just [_X, _Y, _Z]. But it's pure and produces a correct answer for the query quoted.
Q)Find all initial segments of the given list [1, 3, 6 ,9, 8]. i.e. [], [1], [1,3],[1,3,6]
I'm stuck on how to construct the recursive call to segments,I know I have to use an append function but not sure how to bring it all together, I have the following code:
append([], L, L).
append([H|L1], L2, [H|L3]):-
append(L1, L2, L3).
segments([],[]).
segments([H|L1],R):-
Note that #gusbro's solution with append/3 as well as #brebs answer work well if the initial list is given, however, both permit also other solutions that are not lists.
?- L = [1|non_list], append(Segment, _, L).
L = [1|non_list], Segment = []
; L = [1|non_list], Segment = [1]
; false.
?- L = non_list, append(Segment, _, L).
L = non_list, Segment = []
; false.
So even non_list works ; that is a term that is as far remote from a list as possible. Often such extra unwanted generalizations are accepted, in particular if you know that you will never rely upon it. Also this is know as a list prefix of a term.
But if you want to be sure that only lists are considered, use Prolog's dcg-formalism which is the method of choice in many areas.
:- set_prolog_flag(double_quotes, chars). % to make "strings" readable
... --> [] | [_], ... . % any sequence
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
segment_of(Xs, Zs) :-
phrase((seq(Xs), ...), Zs).
?- segment_of(Xs, "abc").
Xs = []
; Xs = "a"
; Xs = "ab"
; Xs = "abc"
; false.
?- segment_of(Xs, non_list).
false.
?- segment_of("ab", L).
L = "ab"
; L = [a,b,_A]
; L = [a,b,_A,_B]
; L = [a,b,_A,_B,_C]
; ... .
Without using append:
% Inc can be an empty list, if Lst is a list (empty or not)
increasing_list([], []).
increasing_list([_|_], []).
increasing_list(Lst, Inc) :-
increasing_list_(Lst, Inc).
% Unify Inc with the current element (Head) of Lst
increasing_list_([Head|_Tail], [Head]).
% Add Head element from Lst to Inc
increasing_list_([Head|Tail], [Head|Inc]) :-
% Loop through the elements in Lst
increasing_list_(Tail, Inc).
Result in swi-prolog:
?- increasing_list([1, 3, 6 ,9, 8], Inc).
Inc = [] ;
Inc = [1] ;
Inc = [1,3] ;
Inc = [1,3,6] ;
Inc = [1,3,6,9] ;
Inc = [1,3,6,9,8]
The aim is to implement the predicate noDupl/2.
The first argument of this predicate is the list to analyze and second argument is the list of numbers which are no duplicate.
I could not understand code below and when I compiled it, it gave an error message that contained is undefined procedure, however as a hint it is written that we can use as predefined predicate contained and notContained. I think I need to define contained and notContained.
noDupl(XS, Res):-
help( XS, [],Res).
help([],_,[]).
help([X|XS],Seen,[X|Res]):-
notContained(X,XS),
notContained(X,Seen),
help(XS, [X|Seen], Res).
help([X|XS],Seen,Res):-
contained(X,Seen),
help(XS, Seen, Res).
help([X|XS],Seen,Res):-
contained(X,XS),
help(XS, [X|Seen], Res).
Could someone please explain me the problem.
The missing definitions might be:
contained(X,[X|_]).
contained(X,[E|Es]) :-
dif(X, E),
contained(X, Es).
notContained(_X, []).
notContained(X, [E|Es]) :-
dif(X, E),
notContained(X, Es).
(I like to call these relations rather memberd/2 and non_member/2.)
The definition you gave extends the relation with an extra argument for the elements considered so far.
To understand the meaning of each clause, read each right-to-left in the direction of the arrow (the :- is a 1970's ASCII-fication of ←). Let's take the first rule:
Provided, that X is not an element of XS, and
provided, that X is not an element of Seen, and
provided, that help(X, [X|Seen], Res) is true,
then also help([X|XS],Seen,[X|Res]) is true.
In other words, if X is neither in the list of visited elements Seen nor in the elements yet to be visited XS, then it does not possess a duplicate.
What is a bit difficult to understand is whether or not the clauses you gave are mutually exclusive - this is, strictly speaking, not your concern, as long as you are only interested in declarative properties, but it is a good idea to avoid such redundancies.
Here is a case, where such redundancy shows:
?- noDupl([a,a,a],U).
U = []
; U = []
; false.
Ideally, the system would give one determinate answer:
?- noDupl([a,a,a], U).
U = [].
Personally, I do not like a lot to split things into too many cases. Essentially, we could have two: it is a duplicate, and it is none.
It is possible to provide a definition that is correct and still fully determinate for the cases where determinism is possible - such as when the first argument is "sufficiently instantiated" (which includes a ground list). Let's see if there are some answers into that direction.
I've annotated your code for you:
noDupl( XS , Res ) :- % Res is the [unique] set of element from the bag XS
help( XS, [],Res) % if invoking the helper succeeds.
. %
help( [] , _ , [] ) . % the empty list is unique.
help( [X|XS] , Seen , [X|Res] ) :- % A non-empty list is unique, if...
notContained(X,XS), % - its head (X) is not contained in its tail (XS), and
notContained(X,Seen), % - X has not already been seen, and
help(XS, [X|Seen], Res). % - the remainder of the list is unique.
help( [X|XS] , Seen , Res ) :- % otherwise...
contained(X,Seen) , % - if X has been seen,
help(XS, Seen, Res). % - we discard it and recurse down on the tail.
help([X|XS],Seen,Res):- % otherwise...
contained(X,XS), % - if X is in the tail of the source list,
help(XS, [X|Seen], Res). % - we discard it (but add it to 'seen').
Your contained/2 and notContained/2` predicates might be defined as this:
contained( X , [X|_] ) :- ! .
contained( X , [Y|Ys] ) :- X \= Y , contained( X , Ys ) .
not_contained( _ , [] ) .
not_contained( X , [Y|Ys] ) :- X \= Y , not_contained(X,Ys) .
Now, I may be missing something in your code, but there's an awful lot of redundancy in it. You could simply write something like this (using the built-ins member/2 and reverse/2):
no_dupes( List , Unique ) :- no_dupes( Bag , [] , Set ) .
no_dupes( [] , V , S ) . % if we've exhausted the bag, the list of visited items is our set (in reverse order of the source)
reverse(V,S) % - reverset it
. % - to put our set in source order
no_dupes( [X|Xs] , V , S ) :- % otherwise ...
( member(X,V) -> % - if X is already in the set,
V1 = V % - then we discard X
; V1 = [X|V] % - else we add X to the set
) , % And...
no_dupes( Xs , V1 , S ) % we recurse down on the remainder
. % Easy!
Can this be done in a pure and efficient way?
Yes, by using
tpartition/4 and (=)/3 like so:
dups_gone([] ,[]).
dups_gone([X|Xs],Zs0) :-
tpartition(=(X),Xs,Ts,Fs),
if_(Ts=[], Zs0=[X|Zs], Zs0=Zs),
dups_gone(Fs,Zs).
Some sample ground queries (all of which succeed deterministically):
?- dups_gone([a,a,a],Xs).
Xs = [].
?- dups_gone([a,b,c],Xs).
Xs = [a, b, c].
?- dups_gone([a,b,c,b],Xs).
Xs = [a, c].
?- dups_gone([a,b,c,b,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a,c],Xs).
Xs = [].
This also works with more general queries. Consider:
?- length(Xs,N), dups_gone(Xs,Zs).
N = 0, Xs = [], Zs = []
; N = 1, Xs = [_A], Zs = [_A]
; N = 2, Xs = [_A,_A], Zs = []
; N = 2, Xs = [_A,_B], Zs = [_A,_B], dif(_A,_B)
; N = 3, Xs = [_A,_A,_A], Zs = []
; N = 3, Xs = [_A,_A,_B], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_A,_B,_A], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_B,_A,_A], Zs = [_B], dif(_A,_B), dif(_A,_B)
; N = 3, Xs = [_A,_B,_C], Zs = [_A,_B,_C], dif(_A,_B), dif(_A,_C), dif(_B,_C)
; N = 4, Xs = [_A,_A,_A,_A], Zs = []
...
i am currently working on a project and i want to implement helper predicate in Prolog
break_down(N, L)
which works as follows
?- break_down(1,L).
L = [1] ;
false.
?- break_down(4,L).
L = [1, 1, 1, 1] ;
L = [1, 1, 2] ;
L = [1, 3] ;
L = [2, 2] ;
L = [4] ;
false.
and so on for any positive integer N .
i have tried and implemented a code which generates only the first result and i cannot get the rest of the results , and this is my code
break_down(1,[1]).
break_down(N,L):-
N>0,
N1 is N-1,
break_down(N1,L1),
append(L1,[1],L).
which generates only the first output result :
L = [1, 1, 1, 1] ;
any suggestion how to edit my code to get the rest ?
Here's a straight-forward recursive implementation using plain integer arithmetic and backtracking:
break_down(N,L) :-
break_ref_down(N,1,L). % reference item is initially 1
break_ref_down(0,_,[]).
break_ref_down(N,Z0,[Z|Zs]) :-
between(Z0,N,Z), % multiple choices
N0 is N-Z,
break_ref_down(N0,Z,Zs). % pass on current item as reference
Sample query:
?- break_down(8,Zs).
Zs = [1,1,1,1,1,1,1,1]
; Zs = [1,1,1,1,1,1,2]
; Zs = [1,1,1,1,1,3]
; Zs = [1,1,1,1,2,2]
; Zs = [1,1,1,1,4]
; Zs = [1,1,1,2,3]
; Zs = [1,1,1,5]
; Zs = [1,1,2,2,2]
; Zs = [1,1,2,4]
; Zs = [1,1,3,3]
; Zs = [1,1,6]
; Zs = [1,2,2,3]
; Zs = [1,2,5]
; Zs = [1,3,4]
; Zs = [1,7]
; Zs = [2,2,2,2]
; Zs = [2,2,4]
; Zs = [2,3,3]
; Zs = [2,6]
; Zs = [3,5]
; Zs = [4,4]
; Zs = [8]
; false.
Here's an implementation based on clpfd.
:- use_module(library(clpfd)).
As the predicate break_downFD/2 is non-recursive, the code is both readable and simple:
break_downFD(N,Zs) :-
length(Max,N), % multiple choices
append(_,Zs,Max),
Zs ins 1..N,
sum(Zs,#=,N),
chain(Zs,#=<), % enforce sequence is non-descending
labeling([],Zs). % multiple choices, possibly
Sample query using SWI-Prolog:
?- break_downFD(6,Zs).
Zs = [1,1,1,1,1,1]
; Zs = [1,1,1,1,2]
; Zs = [1,1,1,3]
; Zs = [1,1,2,2]
; Zs = [1,1,4]
; Zs = [1,2,3]
; Zs = [2,2,2]
; Zs = [1,5]
; Zs = [2,4]
; Zs = [3,3]
; Zs = [6]
; false.
How can I limit the repetition of a number in a list?
What is a suitable constraint in the following code example?
limit(X) :-
length(X,10),
domain(X,1,4),
% WANTED CONSTRAINT: maximum repetition of each number is 5 times.
labeling([],X).
Some sample queries and expected answers:
?- limit([1,1,1,1,1,1,1,1,1]).
false.
?- limit([1,1,1,1,1,2,2,2,2,2]).
true.
This works, L is the list of the number of repetitions of each number from 1 to 4.
:- use_module(library(clpfd)).
limit(X) :-
length(L, 4),
L ins 0..5,
sum(L, #=, 10),
label(L),
maplist(make_list, [1,2,3,4], L, LX),
flatten([LX],X).
make_list(Val, Nb, L) :-
length(L, Nb),
L ins Val .. Val.
The problem is that the numbers are group by values.
The code may be generalized to
limit(X, Min, Max, Len, Rep) :-
Nb is Max -Min + 1,
length(L, Nb),
L ins 0..Rep,
sum(L, #=, Len),
label(L),
numlist(Min, Max, Lst),
maplist(make_list, Lst, L, LX),
flatten([LX],X).
You try : limit(X, 1, 4, 10, 5).
In this answer we use two different clpfd "flavors": sicstus-prolog and gnu-prolog.
:- use_module(library(clpfd)).
limited_repetitions__SICStus(Zs) :-
length(Zs, 10),
domain(Zs, 1, 4),
domain([C1,C2,C3,C4], 0, 5),
global_cardinality(Zs, [1-C1,2-C2,3-C3,4-C4]),
labeling([], Zs).
limited_repetitions__gprolog(Zs) :-
length(Zs, 10),
fd_domain(Zs, 1, 4),
maplist(fd_atmost(5,Zs), [1,2,3,4]),
fd_labeling(Zs).
Simple sample query run with SICStus Prolog version 4.3.2 and GNU Prolog 1.4.4:
?- limited_repetitions__SICStus(Zs). % ?- limited_repetitions__gprolog(Zs).
Zs = [1,1,1,1,1,2,2,2,2,2] % Zs = [1,1,1,1,1,2,2,2,2,2]
; Zs = [1,1,1,1,1,2,2,2,2,3] % ; Zs = [1,1,1,1,1,2,2,2,2,3]
; Zs = [1,1,1,1,1,2,2,2,2,4] % ; Zs = [1,1,1,1,1,2,2,2,2,4]
; Zs = [1,1,1,1,1,2,2,2,3,2] % ; Zs = [1,1,1,1,1,2,2,2,3,2]
; Zs = [1,1,1,1,1,2,2,2,3,3] % ; Zs = [1,1,1,1,1,2,2,2,3,3]
; Zs = [1,1,1,1,1,2,2,2,3,4] % ; Zs = [1,1,1,1,1,2,2,2,3,4]
; Zs = [1,1,1,1,1,2,2,2,4,2] % ; Zs = [1,1,1,1,1,2,2,2,4,2]
... % ...
Let's measure the time required for counting the number of solutions!
call_succeeds_n_times(G_0, N) :-
findall(t, call(G_0), Ts),
length(Ts, N).
?- call_time(call_succeeds_n_times(limited_repetitions__SICStus(_), N), T_ms).
N = 965832, T_ms = 6550. % w/SICStus Prolog 4.3.2
?- call_time(call_succeeds_n_times(limited_repetitions__gprolog(_), N), T_ms).
N = 965832, T_ms = 276. % w/GNU Prolog 1.4.4
In this previous answer we utilized the SICStus Prolog clpfd predicate global_cardinality/2. As an non-constraint alternative, we could also use selectd/3 like this:
multi_selectd_rest([],Ds,Ds).
multi_selectd_rest([Z|Zs],Ds0,Ds) :-
selectd(Z,Ds0,Ds1),
multi_selectd_rest(Zs,Ds1,Ds).
Putting it to good use in limited_repetitions__selectd/3 we define:
limited_repetitions__selectd(Zs) :-
length(Zs, 10),
multi_selectd_rest(Zs,[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4],_).
Again, let's measure the time required for counting the number of solutions!
?- call_time(call_succeeds_n_times(limited_repetitions__selectd(_),N), T_ms).
N = 965832, T_ms = 4600.
Here is a way, but not for sequences:
:- [library(clpfd)].
limit_repetition(Xs, Max) :-
maplist(vs_n_num(Xs, Max), Xs).
vs_n_num(Vs, Max, X) :-
maplist(eq_b(X), Vs, Bs),
% sum(Bs, #=, EqC),
% EqC #=< Max.
sum(Bs, #=<, Max).
eq_b(X, Y, B) :- X #= Y #<==> B.
vs_n_num/3 is an adapted version of what you can find in docs.
Here's a way to delimite sequences:
limit_repetition([X|Xs], Max) :-
limit_repetition(X, 1, Xs, Max).
limit_repetition(X, C, [Y|Xs], Max) :-
X #= Y #<==> B,
( B #/\ C + B #=< Max #/\ D #= C + B ) #\/ ( (#\ B) #/\ D #= 1 ),
limit_repetition(Y, D, Xs, Max).
limit_repetition(_X, _C, [], _Max).
yields
?- length(X,4), X ins 1..4, limit_repetition(X, 1) ,label(X).
X = [1, 2, 1, 2] ;
X = [1, 2, 1, 3] ;
...
Seems the former version is more related to your sample.