Related
I have been asked to
define a predicate subseq/2, with signature subseq(-,+),
which is true when both its arguments are lists, and its first
argument can be constructed by removing zero or more elements
from its second argument.
... with intended solution order:
?- subseq(X, [a, b, c]).
X = [a, b, c] ;
X = [a, b] ;
X = [a, c] ;
X = [a] ;
X = [b, c] ;
X = [b] ;
X = [c] ;
X = [].
My code:
subseq([], []).
subseq([], [_|_]).
subseq([X|XS], [X|YS]) :- subseq(XS, YS).
subseq([X|XS], [_|YS]) :- subseq([X|XS], YS).
My code's solution order:
?- subseq(X, [a, b, c]).
X = []
X = [a]
X = [a, b]
X = [a, b, c]
X = [a, c]
X = [b]
X = [b, c]
X = [c] ;
false.
How do I achieve the intended solution order?
In Prolog, the order of the rules is crucial. To get the desired output, simply change the order of the rules, like this:
subseq([X|XS], [X|YS]) :- subseq(XS, YS).
subseq([X|XS], [_|YS]) :- subseq([X|XS], YS).
subseq([], []).
subseq([], [_|_]).
?- subseq(X,[a,b,c]).
X = [a, b, c]
X = [a, b]
X = [a, c]
X = [a]
X = [b, c]
X = [b]
X = [c]
X = []
Little tweaks can change the order:
sub_list_forwards(Sub, Long) :-
sub_list_forwards_(Long, Sub).
sub_list_forwards_([], []).
% Either pick H, or don't
sub_list_forwards_([H|T], S) :-
(S = Sub ; S = [H|Sub]),
sub_list_forwards_(T, Sub).
Result in swi-prolog:
?- sub_list_forwards(S, [a,b,c]).
S = [] ;
S = [c] ;
S = [b] ;
S = [b, c] ;
S = [a] ;
S = [a, c] ;
S = [a, b] ;
S = [a, b, c].
Or tweak the selection line to be:
(S = [H|Sub] ; S = Sub),
... which results in the order you were given:
?- sub_list_forwards(S, [a,b,c]).
S = [a, b, c] ;
S = [a, b] ;
S = [a, c] ;
S = [a] ;
S = [b, c] ;
S = [b] ;
S = [c] ;
S = [].
Note that neither of these leave an unwanted choicepoint at the end, because they use first-argument indexing on [] vs [H|T] with 1 selection each.
Does the order matter? What would be an optimum order? It probably varies.
In general it is best to put the base case (i.e. [], []) first, for flexibility (and because they sometimes contain a cut).
This is programming, rather than mathematics, so meaningful variable names/initials are far better for readability than using the likes of X and Y continually.
Using (S = [H|Sub] ; S = Sub), produces the sensible:
?- nth1(5, L, e), sub_list_forwards([a,b,c], L).
L = [a, b, c, _, e] ;
L = [a, b, c, _, e, _] ;
L = [a, b, c, _, e, _, _] ;
L = [a, b, c, _, e, _, _, _] ;
... rather than a stack overflow, and so is preferable.
I've been trying to write a simple code, that would behave in this manner:
| ?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? ;
X = [a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
And
| ?- hasCoppiesOf([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = ...
This desire resulted in next piece of code:
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B).
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
And it gives me what I want on the second query, however, the first results in:
?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
It seems to be working fine, but that repetition of the same answers bothers me. It's, probably, a simple mistake, but is there a way to make the output prettier?
And honestly, that a mystery, why Prolog treats two identical arrays as different answers.
Or maybe it's just something wrong with my system?
Edit:
The gentle guidance of the person in the comments helped me to solve this issue. However, if this question will be reading the person who wants to solve exactly the same problem - code not really working well, my apologies.
I think you just made your predicate more complex than it needs to be, probably just overthinking it. A given solution may succeed in multiple paths through the logic.
You can do this without append/3 by aligning the front end of the lists and keep the original list to "reset" on repeats:
% Empty list base cases
dups_list([], []).
dups_list([_|_], []).
% Main predicate, calling aux predicate
dups_list(L, Ls) :-
dups_list(L, L, Ls).
% Recursive auxiliary predicate
dups_list([], [_|_], []).
dups_list([], [X|Xs], [X|Ls]) :-
dups_list(Xs, [X|Xs], Ls).
dups_list([X|Xs], L, [X|Ls]) :-
dups_list(Xs, L, Ls).
Here are some results:
| ?- dups_list(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? a
X = [a,b,a,b]
X = [a,b,a,b,a,b,a,b]
no
| ?- dups_list([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ?
...
| ?- dups_list(A, B).
A = []
B = [] ? ;
A = [_|_]
B = [] ? ;
A = [C]
B = [C] ? ;
A = [C]
B = [C,C] ? ;
A = [C,D]
B = [C,D] ? ;
A = [C]
B = [C,C,C] ? ;
A = [C,D,E]
B = [C,D,E] ? ;
...
There may be a way to simplify the solution just a bit more, but I haven't played with it enough to determine if that's the case.
I think this is what you're trying for...
coppies(Z,Z,[]).
coppies(X,Z,[Y|Ys]):- \+member(Y,Z),coppies(X,[Y|Z],Ys).
coppies(X,Z,[Y|Ys]):- member(Y,Z),coppies(X,Z,Ys).
copies(M,[Y|Ys]):-coppies(M,[],[Y|Ys]).
Input:
copies(X,[1,2,1,2,1,2]).
Output:
X = [2, 1].
BTW I've used some different names instead..
Okay, I got your problem, you want to eliminate the repetitions.
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!. %Change here, place a cut after the termination.
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
This is the change that you need to make.
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!.
A Cut '!' terminates the unwanted backtracking and thereby repetitions.
Hello I wish some advice or words about this task:
Define a statement with three parameters where the first one is a list, the second one is an element (atom or list) and the last one is a list which must accomplish it is equal to the first but first's list' elements which match second parameter,are gone.
Examples:
> elimina([f, e, d, [a, h], a, d, a], a, L)
L = [f, e, d, [a, h], d]
> elimina([f, e, d, [ a, h], a, [d, a]], [a, h], L)
L = [f, e, d, a, [d, a]]
I tried:
elimina([],_,[]).
elimina([X],X,[]).
elimina([X],Y,[X]).
elimina([H|T],H,Result) :-
elimina([T],H,Result).
elimina([H|T],Y,Result):-
elimina([T],H,Result).
I have the doubt about what to write when I shout the recursive call:
elimina([T],H,Result).
Because first I don't know how differently should be the behave when the input second element matchs the head rather than don't matching the head; so I put the same call.
Also I doubt because: Is really needed to put the base case: elimina([X],Y,[X]).? I thought we could pass the exercise with just matching the element to delete with the ones which are really into the list.
Thank you for your time.
There is a very general method how you can test your own code in Prolog. Simply ask Prolog to generate via the most general question all possibilities.
?- elimina([], D, Ys).
Ys = []. % 1: nice!
?- elimina([X], D, Ys).
D = X, Ys = [] % 1: nice!
; Ys = [X] % 2: lacks dif(X, D)
; X = [], D = [], Ys = [] % 3: correct but subsumed by 1
; D = X, Ys = [[]] % 4: incorrect
; X = [], D = [], Ys = [] % 5: correct but subsumed by 1
; X = [], D = [], Ys = [[]] % 6: incorrect
; X = [], D = [], Ys = [] % 7: correct but subsumed by 1
; ... .
For the empty list everything is fine. But for the one-element list, there are many superfluous answers! Actually, there should only be two answers:
D = X, Ys = []
; dif(D, X), Ys = [X].
So now pick some case you want to improve!
Maybe take answer #4 and set D = a, X = a:
?- elimina([a], a, Ys).
Ys = [] % 1: nice
; Ys = [a] % 2: incorrect
; Ys = [[]] % 3: incorrect
; Ys = [] % 4: correct but subsumed by 1
; Ys = [[]] % 5: incorrect and subsumed by 3
; Ys = [] % 6: correct but subsumed by 1
; ... .
So I will pick #3 which actually should fail, but does not
?- elimina([a],a,[[]]).
true
; true
; ... .
Narrow down the culprit by inserting false and some extra equations:
?- elimina([a],a,[[]]).
false.
elimina([],_,[]) :- false.
elimina([X],X,[]) :- false.
elimina([X],Y,[X]) :- Y = a, X = [].
elimina([H|T],H,Result) :- false,
elimina([T],H,Result).
elimina([H|T],Y,Result):- Result = [[]],
elimina([T],H,Result).
Now look at what is left and think about it. Should these remaining rules really hold?
In the remaining visible part there must be an error!
When describing lists, it's usually worthwhile to consider using DCGs for the task. You could describe the relation like so:
elimina(L1,X,L2) :- % L2 is described by
phrase(elimina_x(L1,X),L2). % elimina_x//2
elimina_x([],_X) --> % nothing to delete
[]. % from the empty list
elimina_x([X|Xs],X) --> % if the head of the list equals X
elimina_x(Xs,X). % it's not in the list, same for the tail
elimina_x([X|Xs],Y) --> % if the head of the list
{dif(X,Y)}, % differs from Y
[X], % it is in the list
elimina_x(Xs,Y). % same for the tail
Your example queries yield the desired result.
?- elimina([f, e, d, [a, h], a, d, a], a, L).
L = [f,e,d,[a,h],d] ? ;
no
?- elimina([f, e, d, [ a, h], a, [d, a]], [a, h], L).
L = [f,e,d,a,[d,a]] ? ;
no
Alternatively, you can also express this relation more compactly, using if_/3, (=)/3 and tfilter/3:
dif_t(X,Y,T) :-
if_(X=Y,T=false,T=true).
elimina(L1,X,L2) :-
tfilter(dif_t(X),L1,L2).
The above queries yield the same answers with this version.
I got a problem with lists. What I need to do is to split one list [1,-2,3,-4], into two lists [1,3] and [-2,-4]. My code looks like the following:
lists([],_,_).
lists([X|Xs],Y,Z):- lists(Xs,Y,Z), X>0 -> append([X],Y,Y) ; append([X],Z,Z).
and I'm getting
Y = [1|Y],
Z = [-2|Z].
What am I doing wrong?
If your Prolog system offers clpfd you could preserve logical-purity. Want to know how? Read on!
We take the second definition of lists/3 that #CapelliC wrote in
his answer as a starting point, and replace partition/4 by tpartition/4 and (<)/2 by (#<)/3:
lists(A,B,C) :- tpartition(#<(0),A,B,C).
Let's run a sample query!
?- As = [0,1,2,-2,3,4,-4,5,6,7,0], lists(As,Bs,Cs).
As = [0,1,2,-2,3,4,-4,5,6,7,0],
Bs = [ 1,2, 3,4, 5,6,7 ],
Cs = [0, -2, -4, 0].
As we use monotone code, we get logically sound answers for more general queries:
?- As = [X,Y], lists(As,Bs,Cs).
As = [X,Y], Bs = [X,Y], Cs = [ ], X in 1..sup, Y in 1..sup ;
As = [X,Y], Bs = [X ], Cs = [ Y], X in 1..sup, Y in inf..0 ;
As = [X,Y], Bs = [ Y], Cs = [X ], X in inf..0 , Y in 1..sup ;
As = [X,Y], Bs = [ ], Cs = [X,Y], X in inf..0 , Y in inf..0 .
Here you have. It splits a list, and does not matter if have odd or even items number.
div(L, A, B) :-
append(A, B, L),
length(A, N),
length(B, N).
div(L, A, B) :-
append(A, B, L),
length(A, N),
N1 is N + 1,
length(B, N1).
div(L, A, B) :-
append(A, B, L),
length(A, N),
N1 is N - 1,
length(B, N1).
Refer this:
domains
list=integer*
predicates
split(list,list,list)
clauses
split([],[],[]).
split([X|L],[X|L1],L2):-
X>= 0,
!,
split(L,L1,L2).
split([X|L],L1,[X|L2]):-
split(L,L1,L2).
Output :
Goal: split([1,2,-3,4,-5,2],X,Y)
Solution: X=[1,2,4,2], Y=[-3,-5]
See, if that helps.
Just for variety, this can also be done with a DCG, which is easy to read for a problem like this:
split([], []) --> [].
split([X|T], N) --> [X], { X >= 0 }, split(T, N).
split(P, [X|T]) --> [X], { X < 0 }, split(P, T).
split(L, A, B) :-
phrase(split(A, B), L).
As in:
| ?- split([1,2,-4,3,-5], A, B).
A = [1,2,3]
B = [-4,-5] ? ;
no
It also provides all the possible solutions in reverse:
| ?- split(L, [1,2,3], [-4,-5]).
L = [1,2,3,-4,-5] ? ;
L = [1,2,-4,3,-5] ? ;
L = [1,2,-4,-5,3] ? ;
L = [1,-4,2,3,-5] ? ;
L = [1,-4,2,-5,3] ? ;
L = [1,-4,-5,2,3] ? ;
L = [-4,1,2,3,-5] ? ;
L = [-4,1,2,-5,3] ? ;
L = [-4,1,-5,2,3] ? ;
L = [-4,-5,1,2,3] ? ;
(2 ms) no
Gaurav's solution will also do this if the cut is removed and an explicit X < 0 check placed in the third clause of the split/3 predicate.
There are several corrections to be done in your code.
If you enjoy compact (as readable) code, a possibility is
lists([],[],[]).
lists([X|Xs],Y,Z) :-
( X>0 -> (Y,Z)=([X|Ys],Zs) ; (Y,Z)=(Ys,[X|Zs]) ), lists(Xs,Ys,Zs).
But since (SWI)Prolog offers libraries to handle common list processing tasks, could be as easy as
lists(A,B,C) :- partition(<(0),A,B,C).
I am trying to implement a kind of planner that to a given integer N generates X possible plans with N actions. A action has conditions and restrictions that must be fulfilled, and a list of effects that will be applied to the current state. I implemented the predicates that check the restrictions and conditions and the one that applies the effects. This method that i created already generates a plan with the N actions, but when i press ";" in swi-prolog to see other results, i get the following error:
ERROR: Out of local stack
This is my code:
makePlan(0,_,List):- List = [].
makePlan(N,I,R):- makeSinglePlan(N,I,R).
makeSinglePlan(0, _ ,_).
makeSinglePlan(N,I,[X|LIST]):-
accao(nome : X, condicoes : Y, efeitos : Z, restricoes : W),
checkAllConditions(Y, I),
checkRestrictions(W),
applyEffects(I, Z, Current),
decrement(N, B),
list_to_set(Current, NC),
makeSinglePlan(B,NC,LIST).
decrement(N,B):- B is N-1.
This is how i call the predicate from the console, the first param is the integer N that represents the number of actions that the plans should have, the second is the initial state, and third the return value:
makePlan(2, [clear(b),on(b,a),on(a,mesa),clear(d),on(d,c),on(c,mesa)], R).ยด
Example of an action:
accao(nome : putOn(X,Y), %name
condicoes : [on(X,Z),clear(X),clear(Y)], %conditions
efeitos : [clear(Z),on(X,Y),-on(X,Z),clear(b)], %effects
restricoes : [(Y\==mesa),(X\==Y),(X\==Z),(Y\==Z)]) %restrictions
Auxiliar Predicates:
% 1 - conditions to be checked 2 - current state
checkAllConditions([],_).
checkAllConditions([X|T],L):- checkCond(X,L) , checkAllConditions(T,L) .
checkCond(X,[X|_]).
checkCond(X,[_|T]):-checkCond(X,T).
% 1 - restrictions to be checked
checkRestrictions([]).
checkRestrictions([X|T]):- X, checkRestrictions(T).
% 1 -current state 2 - effects to be applied 3 - result
applyEffects(L,[],L).
applyEffects(L, [-X|YTail], A):- ! ,remove(X, L, B), applyEffects(B,YTail, A).
applyEffects(L, [Y|YTail], A):- insert(Y, L, B), applyEffects(B,YTail, A).
insert(E, L1, [E|L1] ).
remove(_,[],[]).
remove(X, [X|L1], A):- !, remove(X,L1,A).
remove(X, [Y|L1], [Y|A]):- remove(X,L1,A).
Two changes are necessary:
makeSinglePlan(0, _ ,[]).
makeSinglePlan(N,I,[X|LIST]):-
N > 0,
....
The list of actions should end with [], and the rule only applies for N > 0.
?- makePlan(2, [clear(b),on(b,a),on(a,mesa),clear(d),on(d,c),on(c,mesa)], R).
R = [putOn(b, d), putOn(b, a)]
; R = [putOn(b, d), putOn(a, b)]
; R = [putOn(b, d), putOn(a, d)]
; R = [putOn(b, d), putOn(d, b)]
; R = [putOn(b, d), putOn(d, a)]
; R = [putOn(d, b), putOn(d, c)]
; R = [putOn(d, b), putOn(b, c)]
; R = [putOn(d, b), putOn(b, d)]
; R = [putOn(d, b), putOn(c, b)]
; R = [putOn(d, b), putOn(c, d)]
; false.