list intersection, Prolog - prolog

ok, so there's basically 3 tasks this program must carry out:
Parse a sentence given in the form of a list, in this case (and throughout the example) the sentence will be [the,traitorous,tostig_godwinson,was,slain]. (its history, don't ask!) so this would look like:
sentence(noun_phrase(det(the),np2(adj(traitorous),np2(noun(tostig_godwinson)))),verb_phrase(verb(slain),np(noun(slain)))).
use the parsed sentence to extract the subject, verb and object, and output as a list, e.g. [tostig_godwinson,was,slain] using the current example. I had this working too until I attempted number 3.
use the target list and compare it against a knowledge base to basically answer the question you asked in the 1st place (see code below) so using this question and the knowledge base the program would print out 'the_battle_of_stamford_bridge' as this is the sentence in the knowledge base with the most matches to the list in question
so here's where i am so far:
history('battle_of_Winwaed',[penda, king_of_mercia,was,slain,killed,oswui,king_of_bernicians, took_place, '15_November_1655']).
history('battle_of_Stamford_Bridge',[tostig_godwinson,herald_hardrada,was,slain, took_place, '25_September_1066']).
history('battle_of_Boroughbridge',[edwardII,defeated,earl_of_lancaster,execution, took_place, '16_march_1322']).
history('battle_of_Towton',[edwardIV,defeated,henryVI,palm_Sunday]).
history('battle_of_Wakefield',[richard_of_york, took_place,
'30_December_1490',was,slain,war_of_the_roses]).
history('battle_of_Adwalton_Moor',[earl_of_newcastle,defeats,fairfax, took_place, '30_June_1643',battle,bradford,bloody]).
history('battle_of_Marston_Moor',[prince_rupert,marquis_of_newcastle,defeats,fairfax,oliver_cromwell,ironsides, took_place,
'2_June_1644', bloody]).
noun(penda).
noun(king_of_mercia).
noun(oswui).
noun(king_of_bernicians).
noun('15_November_1655').
noun(tostig_godwinson).
noun(herald_hardrada).
noun('25_September_1066').
noun(edwardII).
noun(earl_of_lancaster).
noun('16_march_1322').
noun(edwardIV).
noun(henryVI).
noun(palm_Sunday).
noun(richard_of_york).
noun('30_December_1490').
noun(war_of_the_roses).
noun(earl_of_newcastle).
noun(fairfax).
noun('30_June_1643').
noun(bradford).
noun(prince_rupert).
noun(marquis_of_newcastle).
noun(fairfax).
noun(oliver_cromwell).
noun('2_June_1644').
noun(battle).
noun(slain).
noun(defeated).
noun(killed).
adj(bloody).
adj(traitorous).
verb(defeats).
verb(was).
det(a).
det(the).
prep(on).
best_match(Subject,Object,Verb):-
history(X,Y),
member(Subject,knowledgebase),
member(Object,knowledgebase),
member(Verb,knowledgebase),
write(X),nl,
fail.
micro_watson:- write('micro_watson: Please ask me a question:'), read(X),
sentence(X,Sentence,Subject,Object,Verb),nl,write(Subject),nl,write(Verb),nl,write(Object).
sentence(Sentence,sentence(Noun_Phrase, Verb_Phrase),Subject,Object,Verb):-
np(Sentence,Noun_Phrase,Rem),
vp(Rem,Verb_Phrase),
nl, write(sentence(Noun_Phrase,Verb_Phrase)),
noun(Subject),
member(Subject,Sentence),
noun(Object),
member(Object,Rem),
verb(Verb),
member(Verb,Rem),
best_match(Subject,Object,Verb).
member(X,[X|_]).
member(X,[_|Tail]):-
member(X,Tail).
np([X|T],np(det(X),NP2),Rem):-
det(X),
np2(T,NP2,Rem).
np(Sentence,Parse,Rem):- np2(Sentence,Parse,Rem).
np(Sentence,np(NP,PP),Rem):-
np(Sentence,NP,Rem1),
pp(Rem1,PP,Rem).
np2([H|T],np2(noun(H)),T):-noun(H).
np2([H|T],np2(adj(H),Rest),Rem):- adj(H),np2(T,Rest,Rem).
pp([H|T],pp(prep(H),Parse),Rem):-
prep(H),
np(T,Parse,Rem).
vp([H|[]],verb(H)):-
verb(H).
vp([H|T],vp(verb(H),Rest)):-
verb(H),
pp(T, Rest,_).
vp([H|T],vp(verb(H),Rest)):-
verb(H),
np(T, Rest,_).
As i said i had number 2 working until i tried number 3, now it just prints the parsed sentence out and then give me a 'Error: out of local stack message' any help is greatly appreciated! So at the top is the knowledge base with which we are comparing out list to find the best match, these are called (albeit incorrectly at this stage) by the best_match method, which executes immediately after the sentence method which parses the sentence and extract the key words. Also i apologise if the code is terribly laid out!
Cheers

I assume the person who posted this is never coming back, I wanted to remind myself some prolog, so here it is.
There are two major issues with this code, apart from the fact that there are still some logical problems in some predicates.
Problem 1:
You ignored singleton warnings, and they usually are something not to be ignored. The best match predicate should look like this:
best_match(Subject,Object,Verb):-
history(X,Y),
member(Subject,Y),
member(Object,Y),
member(Verb,Y),
write(X),nl,
fail.
The other warning was about the Sentence variable in the sentence predicate, so it goes like this:
sentence(X,Subject,Object,Verb),nl,write(Subject),nl,write(Verb),nl,write(Object).
sentence(Sentence,Subject,Object,Verb):-
np(Sentence,_,Rem),
vp(Rem,_),
nl,
noun(Subject),
member(Subject,Sentence),
noun(Object),
member(Object,Rem),
verb(Verb),
member(Verb,Rem),
best_match(Subject,Object,Verb).
Problem 2:
I assume you divided the np logic into np and np2 to avoid infinite loops, but then forgot to apply this division just where it was necessary. The longest np clause should be:
np(Sentence,np(NP,PP),Rem):-
np2(Sentence,NP,Rem1),
pp(Rem1,PP,Rem).
If you really wanted to allow more complicated np there, which I doubt, you can do it like this:
np(Sentence,np(NP,PP),Rem):-
append(List1,List2,Sentence),
List1\=[],
List2\=[],
np(List1,NP,Rem1),
append(Rem1,List2,Rem2),
pp(Rem2,PP,Rem).
This way you will not end up calling np with the same arguments over and over again, because you make sure that the sentence checked is shorter each time.
Minor issues:
(How the program works, after the infinite loop problem has been fixed)
The last vp is repeated
I am not sure about your grammar, and e.g. why "defeated" is a noun...
Just to check that the program works I used the sentence [edwardIV,defeated,henryVI,on,palm_Sunday].
I changed "defeated" to a verb, and also changed the last vp clause to:
vp([H|T],vp(verb(H),Rest)):-
verb(H),
np(T,_,Rest1),
pp(Rest1, Rest,_).
For the example sentence I got battle_of_Boroughbridge and battle_of_Towton as results.

Related

Logical task. Why is my code giving the wrong result?

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...

Depth First Search Prolog

I'm trying to solve a water, jug problem (one 7L, one 4L, get 5L in the 7L jug) using dept first search. However something keeps going wrong whenever I try to get a new state back from one of my actions.
Prolog Code
I can't figure out what is going wrong, this is what the output looks like after trace:
enter image description here
Thanks in advance for any help!
You should copy and paste your code into your question; we cannot copy and paste it from your images, which makes it more work to help you, which in turn makes it less likely that we will help.
Some problems I noticed anyway:
Your first rule for go_to_goal/3 does not talk about the relation between ClosedList and Path. You will compute the path but will never be able to communicate it to the caller. (Then again, you also ignore Path in solve/0...) If your Prolog system gives you "singleton variable" warnings, you should never ignore them!
You are using the == operator wrong. The goal State == (5, X) states that at the end you are looking for a pair where the first component is 5 (this part is fine) and the second component is an unbound variable. In fact, after your computations, the second component of the pair will be bound to some arithmetic term. This comparison will always fail. You should use the = (unification) operator instead. == is only used rarely, in particular situations.
If you put a term like X+Y-7 into the head of a rule, it will not be evaluated to a number. If you want it to be evaluated to a number, you must use is/2 in the body of your rules.
Your most immediate problem, however, is the following (visible from the trace you posted): The second clause of go_to_goal/3 tries to call action/2 with a pair (0, 0) as the first argument. This always fails because the first argument of every clause of action/2 is a term state(X, Y). If you change this to state(0, 0) in go_to_goal/3, you should be able to make a little bit of progress.

In Prolog (SWI), how to build a knowledge base of user supplied pairs and assert to be equal

I am very new to Prolog and trying to learn.
For my program, I would like to have the user provide pairs of strings which are "types of".
For example, user provides at command line the strings "john" and "man". These atoms would be made to be equal, i.e. john(man).
At next prompt, then user provides "man" and "tall", again program asserts these are valid, man(tall).
Then the user could query the program and ask "Is john tall?". Or in Prolog: john(tall) becomes true by transitive property.
I have been able to parse the strings from the user's input and assign them to variables Subject and Object.
I tried a clause (where Subject and Object are different strings):
attribute(Subject, Object) :-
assert(term_to_atom(_ , Subject),
term_to_atom(_ , Object)).
I want to assert the facts that Subject and Object are valid pair. If the user asserts it, then they belong to together. How do I force this equality of the pairs?
What's the best way to go about this?
Questions of this sort have been asked a lot recently (I guess your professors all share notes or something) so a browse through recent history might have been productive for you. This one comes to mind, for instance.
Your code is pretty wide of the mark. This is what you're trying to do:
attribute(Subject, Object) :-
Fact =.. [Object, Subject],
assertz(Fact).
Using it works like this:
?- attribute(man, tall).
true.
?- tall(X).
X = man.
So, here's what you should notice about this code:
We're using =../2, the "univ" operator, to build structures from lists. This is the only way to create a fact from some atoms.
I've swapped subject and object, because doing it the other way is almost certainly not what you want.
The predicate you want is assertz/1 or asserta/1, not assert/2. The a and z on the end just tells Prolog whether you want the fact at the beginning or end of the database.
Based on looking at your code, I think you have a lot of baggage you need to shed to become productive with Prolog.
Prolog predicates do not return values. So assert(term_to_atom(... wasn't even on the right track, because you seemed to think that term_to_atom would "return" a value and it would get substituted into the assert call like in a functional or imperative language. Prolog just plain works completely differently from that.
I'm not sure why you have an empty variable in your term_to_atom predicates. I think you did that to satisfy the predicate's arity, but this predicate is pretty useless unless you have one ground term and one variable.
There is an assert/2, but it doesn't do what you want. It should be clear why assert normally only takes one argument.
Prolog facts should look like property(subject...). It is not easy to construct facts and then query them, which is what you'd have to do using man(tall). What you want to say is that there is a property, being tall, and man satisfies it.
I would strongly recommend you back up and go through some basic Prolog tutorials at this point. If you try to press forward you're only going to get more lost.
Edit: In response to your comment, I'm not sure how general you want to go. In the basic case where you're dealing with a 4-item list with [is,a] in the middle, this is sufficient:
build_fact([Subject,is,a,Object], is_a(Subject, Object)).
If you want to isolate the first and last and create the fact, you have to use univ again:
build_fact([Subject|Rest], Fact) :-
append(PredicateAtoms, [Object], Rest),
atomic_list_concat(PredicateAtoms, '_', Predicate),
Fact =.. [Predicate, Subject, Object].
Not sure if you want to live with the articles ("a", "the") that will wind up on the end though:
?- build_fact([john,could,be,a,man], Fact).
Fact = could_be_a(john, man)
Don't do variable fact heads. Prolog works best when the set of term names is fixed. Instead, make a generic place for storing properties using predefined, static term name, e.g.:
is_a(john, man).
property(man, tall).
property(john, thin).
(think SQL tables in a normal form). Then you can use simple assertz/1 to update the database:
add_property(X, Y) :- assertz(property(X, Y)).

Flowpattern doesn't exist

I have been working on a code in prolog for a while now and it is near compiling worthy and all my ideas seem to be solid so it should work when it compiles. It is a program that consults a database file for a list of clauses and then it awaits for a query by the user which it will then pick what information it needs from the sentence and query the database appropriately but there is a block of code that keeps giving me errors complaining that the flowpattern doesn't exist in the standard predicate this may be a silly question but even with all the looking into this I have done i can't find out how to fix this problem if someone could help me out or point me in the right direction that would be greatly appreciated.
Here is the block of code that gives the error:
loop(STR):-
scan(STR,LIST),
filter(LIST,LISroT1),
pars(LIST1,LIST2),
fail.
loop(STR):- STR >< "",readquery(L),loop(L).
readquery(QUERY):-nl,nl,write("Query: "),readln(QUERY).
scan(STR,[TOK|LIST]):-
fronttoken(STR,SYMB,STR1),!,
upper_lower(SYMB,TOK),
scan(STR1,LIST).
the specific line that the compiler complains about is fronttoken(STR,SYMB,STR),!,
any help will be apreaciated thanks!
Since we are looking at an "ex[c]er[p]t" of the code, it's hard to be sure what is going wrong, but the the given evidence points to this: loop/1 is being called before readquery/1 can do its work to populate (bind) the argument STR to loop/1.
Notice that loop/1 calls itself (recursively), and does so in a repeat/fail pattern. But the first time loop/1 runs, there's no indication in the code shown of how argument STR would get populated.
A clearer (more self-contained) code snippet would be like this:
loop :-
readquery(STR),
scan(STR,LIST),
filter(LIST,LISroT1),
pars(LIST1,LIST2),
fail.
loop :- loop.
This makes it clear that predicate loop doesn't actually return any result (and the given code snippet isn't complete enough to make clear what the program as a whole accomplishes). It assumes that the clauses ahead of fail in loop are deterministic, so that in failing, control passes through to the second (recursive) clause of loop/0. If this is not the case, the determinism could be forced by wrapping each call inside once/1.

Are there alternative ways to display a list other than by using loop?

I know on how to display a list by using loop.
For example,
choice(a):-write('This is the top 15 countries list:'),nl,
loop(X).
loop(X):-country(X),write(X),nl,fail.
Unfortunately, I don't know on how to display list by using list. Anyone can guide me?
it's not very clear what it is that you're trying to achieve.
I'm not sure from your description whether you have quite got to grips with the declarative style of Prolog. When you wrote your rule for loop you were providing a set of conditions under which Prolog would match the rule. This is different from a set of procedural instructions.
If you want to collect all the countries into a list you can use the setof rule like follows
top_countries(Cs):-
setof(C, country(C), Cs).
This will return a list [] of the countries matched by the rule.
If you wanted to output each element of this list on a new line you could do something like the following recursive function.
write_list([]).
write_list([H|T]):-
write(H),nl,
write_list(T).
The first rule matches the base case; this is when there are no elements left in the list. At this point we should match and stop. The second rule matches (unifies) the head of the list and writes it to screen with a newline after it. The final line unifies the tail (remainder) of the list against the write_list function again.
You could then string them together with something like the following
choice(a):-
write('This is the top 15 countries list:'),nl,
top_countries(X),
write_list(X).
Things to note
Try not to have singleton variables such as the X in your choice rule. Variables are there to unify (match) against something.
Look into good declarative programming style. When you use functions like write it can be misleading and tempting to treat Prolog in a procedural manner but this will just cause you problems.
Hope this helps
write/1 doesn't only write strings, it writes any Prolog term. So, though Oli has given a prettier write_list, the following would do the job:
choice(Countries):-write('This is the top 15 countries list:'),nl,write(Countries).

Resources