I have a prolog homework, which should work like this:
singles([1,2,3,2,2,4,1], [3,4]).
true
Now I've figured out I should test if one element is single in the list then put all the single element together..then I wrote down:
singles(L,SL):-findall(X,isSingle(X,L),SL).
isSingle(X,L):-member(X,L),append(Y,[X|Z],L),not(member(X,L1)),append(Y,Z,L1).
in the isSingle function the X should be in List L but not in the new List L1 without X, like 1 is in [2,1,3] but not in [2,3], but sadly the whole thing doesn't work like I thought :(
I think the problem is in the isSingle part, can anyone help me?
Switch the order of not(member(X,L1)) and append(Y,Z,L1) and your code works. I'm no Prolog expert, so I'm not entirely sure about this, but, going through the trace, it seems to have to do with the subtleties of using not. You're forcing the evaluation of member on L1 before it has been unified in append(Y,Z,L1) bit.
singles(List,SelectList) :-
singles(List,List,SelectList).
singles([],List,[]).
singles([A|R1],List,[A|R2]) :-
unique(A,List),
singles(R1,List,R2).
singles([A|R1],List,R2) :-
\+(unique(A,List)),
singles(R1,List,R2).
unique(A,List) :-
append(L0,[A|R],List),
\+(append(_,[A|_],L0)),
\+(append(_,[A|_],R)).
Related
I defined my knowledge base as:
edge(mammal,isa,animal).
edge(human,isa,mammal).
edge(simba,isa,human).
edge(animal,swim,bybirth).
edge(human,swim,mustlearn).
path(X,Y) :- edge(X,isa,Y).
path(X,Y) :- edge(X,isa,Z), path(Z,Y).
swim(X,Y) :- edge(X,swim,Y).
swim(X,Y) :- path(X,Z), swim(Z,Y).
Now, to use the above knowledge base, I use the following:
?- swim(simba,bybirth).
?- swim(simba,mustlearn).
And for both the queries, Prolog returns true. I want Prolog to check for the property swim locally first, then look at the direct parent, and so on in a hierarchical fashion. And it should stop searching as soon as we know that Simba "mustlearn" to swim, and shouldn't look any further. Thus, it should return false for the first query and true for the second.
I know it has to be done by limiting backtracking. I tried using the cut and not operators, but couldn't succeed. Is there a way to achieve this?
I tried it and ran into a problem too. I thought this might work:
swim(X,Y) :- once((edge(X,swim,Y); path(X,Z), swim(Z,Y))).
It doesn't work, because if Y is already instantiated on the way in, the first step will fail to unify and it will try the second route going through the human intermediate. So even though the query only produces one result, it can be fooled into producing swim(simba, bybirth). The solution is to force Prolog to commit to a binding on another variable and then check that binding after the commitment:
swim(X,Y) :-
once((edge(X,swim,Method); path(X,Z), swim(Z,Method))),
Method = Y.
This tells Prolog, there is only one way to get to this method, so find that method, and then it must be Y. If you find the wrong method, it won't go on a search, it will just fail. Try it!
I am trying to get a predicate to relate from 1 fact to another fact and to keep going until a specified stopping point.
For example,
let's say I am doing a logistics record where I want to know who got a package from who, and where did they get it from until the end.
Prolog Code
mailRoom(m).
gotFrom(annie,brock).
gotFrom(brock,cara).
gotFrom(cara,daniel).
gotFrom(daniel,m).
gotFrom(X,Y) :- gotFrom(Y,_).
So what I am trying to do with the predicate gotFrom is for it to recursively go down the list from what ever point you start (ex: gotFrom(brock,Who)) and get to the end which is specified by m, which is the mail room.
Unfortunately when I run this predicate, it reads out,
Who = annie.
Who = brock.
Who = cara.
etc.etc....
I tried stepping through the whole thing but Im not sure where it goes from brock to annie, to cara and all the way down till it cycles through trues for infinity. I have a feeling that it has something to do with the wildcard in the function (_), but Im not sure how else I could express that part of the function in order for the predicate to search for the next fact in the program instead of skipping to the end.
I tried using a backcut (!) in my program but it gives me the same error.
Any help is greatly appreciated. I don't want code I just want to know what I am doing wrong so I can learn how to do it right.
Thanks.
I'm afraid this rule is meaningless:
gotFrom(X,Y) :- gotFrom(Y,_).
There is nothing here to constrain X or Y to any particular values. Also, the presence of singleton variable X and the anonymous variable _ means that basically anything will work. Try it:
?- gotFrom([1,2,3], dogbert).
true ;
true ;
What I think you're trying to establish here is some kind of transitive property. In that case, what you want is probably more like this:
gotFrom(X,Z) :- gotFrom(X, Y), gotFrom(Y, Z).
This produces an interesting result:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
ERROR: Out of local stack
The reason for the problem may not be immediately obvious. It's that there is unchecked recursion happening twice in that rule. We recursively unify gotFrom/2 and then we recursively unify it again. It would be better to break this into two predicates so that one of them can be used non-recursively.
got_directly_from(annie,brock).
got_directly_from(brock,cara).
got_directly_from(cara,daniel).
got_directly_from(daniel,m).
gotFrom(X,Y) :- got_directly_from(X, Y).
gotFrom(X,Z) :- got_directly_from(X, Y), gotFrom(Y, Z).
This gives us the desired behavior:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
false.
Notice this one is resilient to my attack of meaningless data:
?- gotFrom([1,2,3], dogbert).
false.
Some general advice:
Never ignore singleton variable warnings. They are almost always a bug.
Never introduce a cut when you don't understand what's going on. The cut should be used only where you understand the behavior first and you understand how the cut will affect it. Ideally, you should try to restrict yourself to green cuts—cuts that only affect performance and have no observable effects. If you don't understand what Prolog is up to, adding a red cut is just going to make your problems more complex.
I hope that someone can help me. Is it possible inference from a situation S different to s0 in Prolog?
I have a s0 (initial situation) like this:
isoven(oven).
isoff(oven,s0).
ison(X,do(a,S)):- a=switchOn(X),isoven(X); isOff(X,S),\+ a=swicthOff(X). (fluent inon)
If I prompted:
?- isOn(oven,s0).
false.
?- ison(oven,do(swicth(oven)s0)).
true
It would be nice if existed a command like "save(do(swicth(oven)s0)) to S'" in order to obtained a result like this:
?- ison(oven,S').
true.
Prolog is not magic, you need to implement things properly.
It appears you want to use situation calculus, there's plenty of material online about it.
Also:
a=switchOn(X)
This is meaningless, it always fail. You need a variable there (the first letter must be upper case)
I have a predicate "lookupOptions" which returns one by one some lists (Menus).
I'm trying to get it to satisfy the case of multiple inputs. I can return a single set of options as follows, by reading the head of the "list_places" list.
find_options(Restaurant,Town,Menu) :- lookupOptions(Restaurant,H,Menu), list_places(Town,[H|T])
But, I'm not able to get it to iterate.
I have tried a lot of things, these were my best efforts so far.
a) standard enough iteration, but it wont resolve ...
doStuff(X,[],_).
doStuff(Restaurant,[H|T],_):- lookupOptions(Resturant,H,_), doStuff(Restaurant,T,_).
find_options(Restaurant,Town,Menu) :- doStuff(Restaurant,[H|T],Menu), list_places(Town,[H|T]).
b) expanding the goal predicate ...
find_options(_,Town,[H|T],_)
find_options(Restaurant,Town,Menu) :- find_options(Restaurant,Town,[],Menu).
find_options(Restaurant,Town,X,Menu) :- list_places(Town,X).
find_options(Restaurant,Town,[H|T],Menu) :- lookupOptions(Restaurant,[H],Menu), find_options(Restaurant,Town,T,Menu).
Would either of these work ? if the pattern was written correctly. Or if there was an appropriate cut put in place?
Any help most appreciated ...
It's no clear on what you want iterate. Prolog uses backtracking to examine all alternatives, then you should start backtracking if you are after some alternative, or use the all solutions family.
Now I think you want simply declare there could be more find_options(Restaurant,Town,Menu). Then try replacing the head match [H|T] with this:
find_options(Restaurant,Town,Menu) :-
lookupOptions(Restaurant,H,Menu),
list_places(Town, Places),
member(H, Places).
BTW T is a singleton in your original rule. This could be a hint for the need of generalize it.
I have written the following code in SWI-Prolog:
:- dynamic state_a/1 .
:- dynamic state_b/1 .
:- dynamic state_c/1 .
state_a([1,2,3,4,5,0]).
state_b([0]).
chop(LIST,HEAD,TAIL) :- LIST=[HEAD|TAIL].
move_ab :- !,state_a(X),
chop(X,Ha,Ba),
Ha>0,
state_b(Y),
chop(Y,Hb,Bb),!,
(Ha<Hb ; Hb =:= 0),
asserta(state_a(Ba)),asserta(state_b([Ha|Y])),
retract(state_a(X)), retract(state_b(Y));
write('Wrong Move.Choose Another').
There are 2 OR(;) in my code. When I ask move_ab in Prolog for the first time all the conditions before the second OR are true so i get the answer true from Prolog.
But the second time I ask move_ab in Prolog I get just the answer false.
I don't know how this can happen. Some of the conditions before the second OR are not true so Prolog should check the condition after the second OR and write me the message Wrong Move.Choose Another..
I tried using () to group the conditions but I still get the same message.
Any idea about what is going on? By the way I am a newb in Prolog, just started 2 days ago :)
The problem lies in the use of cut (!/0) before the conditions are properly tested. Cut removes choice points. Here it means that the choices are removed before you even test anything. So if the tests fail, everything fails !
BTW, manipulating the database is maybe not the best idea there. To represent states, you could use global variables as follows :
:- nb_setval(state_a, [1,2,3,4,5,0]).
:- nb_setval(state_b, [0]).
move_ab :-
nb_getval(state_a, [Ha|Ta]),
Ha > 0,
nb_getval(state_b, [Hb|Tb]),
(Ha < Hb ; Hb =:= 0),
nb_setval(state_a, Ta),
nb_setval(state_b, [Ha, Hb|Tb]),
!
;
write('Wrong Move.Choose Another').
A general advice given to beginners in prolog is to stay away from database manipulation if possible, as often problems are solvable without it. Here though it could be justified, but global variables will be faster and easier to manipulate.