I'm trying to write some rules that will tell about the number of blocks in a stack (not the data structure, just a location). The rule stack return true for every block in a stack.
Specifically, is zero/one/two the number of blocks in X?
num_blocks(X,zero) :- \+stack(X,_).
num_blocks(X,one) :- stack(X,A),\+stack(X,B),A\=B.
So, num_blocks(X,zero) works as intended, but the other one doesn't. My thought process is that if we can find one block(A) and we cannot find a second unique block(B), then there is only one block in X stack. However, I still keep getting false back.
What you intended (as per your description) is to check whether there is no other block in the stack. But you are just applying not to stack(X,B) which means there is no block in the stack X, and it \+stack(X,B) succeded it would leave B as is (uninstantiated).
I think what you want for the second clause is the negation of the conjunction of stack(X,B) and A\=B, that is:
num_blocks(X,one) :-
stack(X,A),
\+ ( stack(X,B), A\=B ).
Related
Unfortunately, I cannot give the full text of the problem for some reason. Therefore, I will try to describe the main point.
There was a murder at the hotel in room 4. 6 visitors are suspected who came to visit someone in one of the 6 hotel rooms at different intervals (These are all facts).
Then all the suspects were interviewed, some evidence was considered and information was received from the receptionist (These are the rules).
You need to find out who was where at what time. Well, and therefore who is the killer.
my problem
I am not getting the correct result.
When calling
guest(brown, R, T).
i get false (brawn must be a killer)
and basically when i call the function
solution(Guests).
then I get a very large number of lists. And the rules are not followed in them. Why is that?
result lists screenshoot
In short, I have a suspicion that these rules work somehow separately. But I could be wrong, because in the prologue I am a complete zero. What's my mistake?
P.S. If necessary, I can try to write the full text of the assignment. The only problem is that the text is in a different language from an old book that was scanned..
The reason why your query fails is the following program fragment. I obtained it by systematically generalizing away goal after goal by adding a * in front. Because this fragment fails, also your original program will fail. I am sure it will be evident to you how to interpret this:
:- op(950, fy, *). % auxiliary definition
*_.
:- initialization(guest(brown, _R, _T)). % your failing query
evidence(taylor,R,_):- *not(R=5).
evidence(white,R,_):- *not(R=5).
evidence(smith,R,_):- *not(R=1), *not(R=3), *not(R=6), *not(R=5).
evidence(green,R,_):- *not(R=3), *not(R=6).
guest(N,R,T):-
*interrogation(N,R,T),
evidence(N,R,T),
*receptionist(N,R,T).
Just a remark, instead of not(A=B) rather use dif(A,B). It's the 21st century...
Trying to implement following predicate, which takes on input
list of lists - one list = one tested graph T (as edges)
graph G itself (as edges)
and tests whether T includes all of the vertices of G. If it does(true) should return it. Basically it's list filtering.
What I have so far is:
covb([],G).
covb([H|R],G) :-
isItCov(G,H), covb(R,G).
isItCov([],H).
isItCov([V-W|R],H) :-
vertex(V,H),
vertex(W,H),
isItCov(R,H).
vertex(V,[V-_|G]).
vertex(V,[_-V|G]).
vertex(V,[_|G]):- vertex(V,G).
For covb([[a-c,c-b,c-d]],[a-b,a-c,a-d,c-d,b-c]) works fine(true). For covb([[a-c]],[a-b,a-c,a-d,c-d,b-c]) works fine too (false). I got an issue while I call it with multiple lists like covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]). which should work only for the first one.
I actually got two questions -
Why does it work for one list only?
I want to return items of lists of lists which passed the condition and returned true (that's the filtering part). How should I do that?
First of all, your program has a number of singleton variable warnings. Do not ignore singleton variable warnings. They can hide real bugs. Also, since more experienced Prolog users here know that programs with singleton variable warnings are not even worth running, they will (a) just see the warnings and decide that they are no longer interested in trying to help you, or (b) fix the warnings on their side, but then by definition they will be working on a program that is no longer the program you posted!
Now for your questions.
Why does it work for one list only?
It's really not clear what you are asking here, or just above with "covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]). which should work only for the first one."
This query does fail:
?- covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]).
false.
This comes down to testing each of the two lists:
?- isItCov([a-b,a-c,a-d,c-d,b-c], [a-c,c-b,c-d]).
true .
?- isItCov([a-b,a-c,a-d,c-d,b-c], [a-c]).
false.
The first list does cover the graph, while the second doesn't. Overall, your definition of covb/2 is written to succeed if all lists cover the graph. This is not the case, so your covb/2 query fails.
Was this what you wanted to know?
I want to return items of lists of lists which passed the condition and returned true (that's the filtering part). How should I do that?
You could see if your Prolog's documentation has something for the word "filter". On SWI-Prolog you can do this:
?- apropos(filter).
true.
This will point you to the include/3 predicate, which seems to do what you want:
?- include(isItCov([a-b,a-c,a-d,c-d,b-c]), [[a-c,c-b,c-d],[a-c]], Covers).
Covers = [[a-c, c-b, c-d]].
If you want to write a filter predicate for your concrete application, it might look something like this:
graph_covers(_Graph, [], []).
graph_covers(Graph, [Nodes|NodesRest], Covers) :-
( isItCov(Graph, Nodes)
-> Covers = [Nodes|CoversRest]
; Covers = CoversRest ),
graph_covers(Graph, NodesRest, CoversRest).
This is similar to your predicate, it just adds an extra argument to collect those node lists for which isItCov/2 succeeded. If it did not succeed, it continues with a list not containing that current node list.
?- graph_covers([a-b,a-c,a-d,c-d,b-c], [[a-c,c-b,c-d],[a-c]], Covers).
Covers = [[a-c, c-b, c-d]] ;
false.
This is my prolog code, which gave me the following error:
ERROR: Out of global stack
hasA(S,A):- name(S,L1),
compar(L1,A).
compar([H1,H2|T1],T1):- H1 == 1575, H2 == 1740.
neda(H,A):- hasA(H,Z1),
append(A,[1575,1740],A),
state(Z1,Z2),
append(A,Z2,A).
state([H|T],T):- H == 32.
state(A,A).
What is wrong? Can you help me with it?
Assuming that you call neda(H,A) with A being a free variable you end up calling append(A,[1575,1740],A) with A being a free variable as well. However, traditionally, append is implemented as
append([],Ys,Ys).
append([X|Xs],Ys,[X|Zs]) :- append(Xs,Ys,Zs).
Unification of append(A,[1575,1740],A) with append([],Ys,Ys) fails since it requires A to be [], on the one hand, and [1575,1740], on the other hand. Hence, Prolog tries to unify append(A,[1575,1740],A) with append([X|Xs],Ys,[X|Zs]) and succeeds with {A/[X|Xs], Ys/[1575,1740], Xs/Zs} which leads to the call append(Xs,[1575,1740],Xs) and the process repeats, i.e., Prolog enters an infinite recursion and ultimately runs out of stack.
If I guess your intention correctly, you first would like to append [1575,1740] to A and then to append Z2. This would mean that you need to introduce two new variables, say A1 and A2, to record the state of A after each appending step:
neda(H,A):- hasA(H,Z1),
append(A,[1575,1740],A1),
state(Z1,Z2),
append(A1,Z2,A2).
Beware, however, that with A being a free variable on backtracking this code will generate lists of increasing length; is this what you want?
I am a total beginner at Prolog. I am struggling with creating a rule, which takes a list as parameter and passes the list onto another rule. Here is my code:
combine([], '').
combine([L|List], Total) :-
combine(List, CombinedRest),
atom_concat(L, CombinedRest, Total).
findHeadline([W|Words], Combined) :-
combine(Words, Combined).
findHeadline2([Words], Combined) :-
combine(Words, Combined).
findHeadline works as expected, but findHeadline2 does not. Here is the output:
1 ?- findHeadline([billig, enkeltmand], Combination).
Combination = enkeltmand.
2 ?- findHeadline2([billig, enkeltmand], Combination).
false.
The output I was expecting from findHeadline was:
Combination = billigenkeltmand.
How can it be that this does not work?
I tried to utilize trace in SWI-prolog, but it gave me no clue whatsoever, as the findHeadline rule just exits immediately and does not call the combine rule at all.
It is not very clear what it is exactly that you are after. If you just want to concatenate a list of atoms to get one atom, use atomic_list_concat/2 available in SWI-Prolog:
?- atomic_list_concat([foo, bar, baz], C).
C = foobarbaz.
At the moment, your findHeadline2/2 reads:
"Take a list containing exactly one element, and combine/2 that element."
This is not what you are after, I have the feeling.
Your findHeadline/2, on the other hand, says:
"Take a list of at least one element, and combine/2 all elements except the first".
This is important: never ever ignore compilation warnings. You get code that does something, but you can be almost certain that it does not do what you want it to do, which is bad, or that if someone else reads your code, they will be confused, which is also bad.
How do I define a rule that the user cannot query?
I only want the program itself to call this rule through another rule.
Ex:
rule1():- rule2().
rule2():- 1<5.
?-rule1().
true
?-rule2().
(I don't know what the answer will be, I just want this query to fail!)
Use a Logtalk object to encapsulate your predicates. Only the predicates that you declare public can be called (from outside the object). Prolog modules don't prevent calling any predicate as using explcit qualification bypasses the list of explicitly exported predicates.
A simple example:
:- object(rules).
:- public(rule1/1).
rule1(X) :-
rule2(X).
rule2(X) :-
X < 5.
:- end_object.
After compiling and loading the object above:
?- rules::rule1(3).
true.
?- rules::rule2(3).
error(existence_error(predicate_declaration,rule2(3)),rules::rule2(3),user)
If you edit the object code and explicitly declare rule2/1 as private you would get instead the error:
?- rules::rule2(3).
error(permission_error(access,private_predicate,rule2(3)),rules::rule2(3),user)
More information and plenty of examples at http://logtalk.org/
First, some notes:
I think you mean "predicate" instead of "rule". A predicate is a name/k thing such as help/0 (and help/1 is another) and can have multiple clauses, among them facts and rules, e.g. length([], 0). (a fact) and length([H|T], L) :- ... . (a rule) are two clauses of one predicate length/2.
Do not use empty parenthesis for predicates with no arguments – in SWI-Prolog at least, this will not work at all. Just use predicate2 instead of predicate2() in all places.
If you try to call an undefined predicate, SWI-Prolog will say ERROR: toplevel: Undefined procedure: predicate2/0 (DWIM could not correct goal) and Sicstus-Prolog will say {EXISTENCE ERROR: predicate2: procedure user:predicate2/0 does not exist}
Now, to the answer. Two ideas come to my mind.
(1) This is a hack, but you could assert the predicate(s) every time you need them and retract them immediately afterwards:
predicate1 :-
assert(predicate2), predicate2, retractall(predicate2).
If you want a body and arguments for predicate2, do assert(predicate2(argument1, argument2) :- (clause1, clause2, clause3)).
(2) Another way to achieve this would be to introduce an extra argument for the predicate which you do not want to be called by the user and use it for an identification that the user cannot possibly provide, but which you can provide from your calling predicate. This might be a large constant number which looks random, or even a sentence. This even enables you to output a custom error message in case the wrong identification was provided.
Example:
predicate1 :-
predicate2("Identification: 2349860293587").
predicate2(Identification) :-
Identification = "Identification: 2349860293587",
1 < 5.
predicate2(Identification) :- Identification \= "Identification: 2349860293587",
write("Error: this procedure cannot be called by the user. Use predicate1/0 instead."),
fail.
I don't use the equivalent predicate2("Identification: 2349860293587") for the first clause of predicate2/0, because I'm not sure where the head of the clause might appear in Prolog messages and you don't want that. I use a fail in the end of the second clause just so that Prolog prints false instead of true after the error message. And finally, I have no idea how to prevent the user from looking up the source code with listing(predicate2) so that will still make it possible to simply look up the correct identification code if s/he really wants to. If it's just to keep the user from doing accidental harm, it should however suffice as a protection.
This reminds me to facility found in Java. There one can query the
curent call stack, and use this to regulate permissions of calling
a method. Translated to Prolog we find in the old DEC-10 Prolog the
following predicate:
ancestors(L)
Unifies L with a list of ancestor goals for the current clause.
The list starts with the parent goal and ends with the most recent
ancestor coming from a call in a compiled clause. The list is printed
using print and each entry is preceded by the invocation number in
parentheses followed by the depth number (as would be given in a
trace message). If the invocation does not have a number (this will
occur if Debug Mode was not switched on until further into the execution)
then this is marked by "-". Not available for compiled code.
Since the top level is usually a compiled predicate prolog/0, this could be
used to write a predicate that inspects its own call stack, and then decides
whether it wants to go into service or not.
rule2 :- ancestors(L), length(L,N), N<2, !, write('Don't call me'), fail.
rule2 :- 1<5.
In modern Prologs we don't find so often the ancestors/1 predicate anymore.
But it can be simulated along the following lines. Just throw an error, and
in case that the error is adorned with a stack trace, you get all you need:
ancestors(L) :- catch(sys_throw_error(ignore),error(ignore,L),true).
But beware stack eliminiation optimization might reduce the stack and thus
the list returned by ancestors/1.
Best Regards
P.S.: Stack elimination optimization is already explained here:
[4] Warren, D.H.D. (1983): An Abstract Prolog Instruction Set, Technical Note 309, SRI International, October, 1983
A discussion for Jekejeke Prolog is found here:
http://www.jekejeke.ch/idatab/doclet/prod/en/docs/10_pro08/13_press/03_bench/05_optimizations/03_stack.html