In Prolog how can I cut redundant answers - prolog

I am working on a dictionary-like program with prolog, and my code goes like this:
define(car,vehicle).
define(car,that).
define(car,has).
define(car,four).
define(car,wheels).
define(wheels,round).
define(wheels,object).
define(wheels,used).
define(wheels,in).
define(wheels,transportation).
defined(X):-define(X,_).
anotherdefined(X):- \+ undefined(X).
undefined(X):- \+define(X,_).
I am trying to write a defined/1 predicate which will give me:
?-defined(X).
X = car ;
X = wheels ;
false.
Yet, my defined/1 gives me X=car. five times (naturally) for everytime it counters define(car,_).
and my anotherdefined/1 gives me only true. What is the method to stop prolog backtracking to the other instances of define(car,_).,and skip to define(wheels,_).?
Edit: I have written the following lines to get the result I want with givedefinedword/1,
listdefined(X):-findall(Y,defined(Y),Z),sort(Z,X).
givedefinedword(X):-listdefined(List),member(X,List).
However since I wanted an efficient predicate (which I will use in many others) it beats the purpose. This predicate does too much process.
Or, Would it be better to use a predicate that modifies the code? say prepares a list of defined words, and modifies it when new definitions are added.
Thanks.

If you change define to relate items and lists, like
definelist(car, [vehicle, that, has, four, wheels]).
% etc.
defined(X) :- definelist(X, _).
then defined will no longer produce duplicates, nor require linear space.
Of course, a query define(X, Y) must now be performed as definelist(X, L), member(Y, L). If you want this to be efficient as well, you may need to duplicate all definitions.

What are you trying to achieve with your program? It seems that you want to have facts in the form:
"A car is a vehicle that has four wheels"
"Wheels are round objects used in transportation" (a bit vague)
How are you going to use these facts? #larsmans suggestion if perfectly fine, if you want to just have your statement as a "sentence". It really depends what you will do with the information though.
Consider structuring the information in your database:
is(car, vehicle).
is(bicycle, vehicle).
is(boat, vehicle).
has(car, wheel(four)).
has(car, motor).
has(bicycle, wheel(two)).
Given this database, you can at least ask a question like, "what vehicles are there?", "does a bicycle have a motor?", or maybe, "how many wheels does a car have?", or "which vehicles have no wheels?"
?- is(X, vehicle).
?- has(bicycle, motor).
?- has(car, wheel(N)).
?- is(X, vehicle), \+ has(X, wheel(_)).
and so on.
Once you have defined your problem better, you can define your data structures better, which will make writing a program to solve your problem easier.

Related

Prolog - Return result instead of printing in algorithm

I know there is technically no 'return' in Prolog but I did not know how to formulate the question otherwise.
I found some sample code of an algorithm for finding routes between metro stations. It works well, however it is supposed to just print the result so it makes it hard to be extended or to do a findall/3 for example.
% direct routes
findRoute(X,Y,Lines,Output) :-
line(Line,Stations),
\+ member(Line,Lines),
member(X,Stations),
member(Y,Stations),
append(Output,[[X,Line,Y]],NewOutput),
print(NewOutput).
% needs intermediate stop
findRoute(X,Y,Lines,Output) :-
line(Line,Stations),
\+ member(Line,Lines),
member(X,Stations),
member(Intermediate,Stations),
X\=Intermediate,Intermediate\=Y,
append(Output,[[X,Line,Intermediate]],NewOutput),
findRoute(Intermediate,Y,[Line|Lines],NewOutput).
line is a predicate with an atom and a list containing the stations.
For ex: line(s1, [first_stop, second_stop, third_stop])
So what I am trying to do is get rid of that print at line 11 and add an extra variable to my rule to store the result for later use. However I failed miserably because no matter what I try it either enters infinite loop or returns false.
Now:
?- findRoute(first_stop, third_stop, [], []).
% prints [[first_stop,s1,third_stop]]
Want:
?- findRoute(first_stop, third_stop, [], R).
% [[first_stop,s1,third_stop]] is stored in R
Like you, I also see this pattern frequently among Prolog beginners, especially if they are using bad books and other material:
solve :-
.... some goals ...
compute(A),
write(A).
Almost every line in the above is problematic, for the following reasons:
"solve" is imperative. This does not make sense in a declarative languague like Prolog, because you can use predicates in several directions.
"compute" is also imperative.
write/1 is a side-effect, and its output is only available on the system terminal. This gives us no easy way to actually test the predicate.
Such patterns should always simply look similar to:
solution(S) :-
condition1(...),
condition2(...),
condition_n(S).
where condition1 etc. are simply pure goals that describe what it means that S is a solution.
When querying
?- solution(S).
then bindings for S will automatically be printed on the toplevel. Let the toplevel do the printing for you!
In your case, there is a straight-forward fix: Simply make NewOutput one of the arguments, and remove the final side-effect:
route(X, Y, Lines, Output, NewOutput) :-
line(Line, Stations),
\+ member(Line, Lines),
member(X, Stations),
member(Y, Stations),
append(Output, [[X,Line,Y]], NewOutput).
Note also that I have changed the name to just route/5, because the predicate makes sense also if the arguments are all already instantiated, which is useful for testing etc.
Moreover, when describing lists, you will often benefit a lot from using dcg notation.
The code will look similar to this:
route(S, S, _) --> []. % case 1: already there
route(S0, S, Lines) --> % case 2: needs intermediate stop
{ line_stations(Line, Stations0),
maplist(dif(Line), Lines),
select(S0, Stations0, Stations),
member(S1, Stations) },
[link(S0,Line,S1)],
route(S1, S, [Line|Lines]).
Conveniently, you can use this to describe the concatenation of lists without needing append/3 so much. I have also made a few other changes to enhance purity and readability, and I leave figuring out the exact differences as an easy exercise.
You call this using the DCG interface predicate phrase/2, using:
?- phrase(route(X,Y,[]), Rs).
where Rs is the found route. Note also that I am using terms of the form link/3 to denote the links of the route. It is good practice to use dedicated terms when the arity is known. Lists are for example good if you do not know beforehand how many elements you need to represent.

Prolog taking inverse of a predicate

I got a database that looks like
hasChild(person1, person2).
hasChild(person1, person3).
hasChild(person4, person5).
Which means that (for example) person1 has child named person2.
I then create a predicate that identifies if the person is a parent
parent(A):- hasChild(A,_).
Which identifies if the person is a parent, i.e. has any children
Then I try to create a predicate childless(A) that should return true if the user doesn't have any children which is basically an inverse of parent(A).
So I have 2 questions here:
a) is it possible to somehow take an "inverse" of a predicate, like childless(A):-not(parent(A)). or in any other way bypass this using the hasChild or any other method?
b) parent(A) will return true multiple times if the person has multiple children. Is it possible to make it return true only once?
For problem 1, yes. Prolog is not entirely magically delicious to some because it conflates negation and failure, but you can definitely write:
childless(X) :- \+ hasChild(X, _).
and you will see "true" for people that do not have children. You will also see "true" for vegetables, minerals, ideologies, procedures, shoeboxes, beer recipes and unfeathered bipeds. If this is a problem for you, a simple solution is to improve your data model, but complaining about Prolog is a very popular alternative. :)
For problem 2, the simplest solution is to use once:
parent(A) :- once(hasChild(A, _)).
This is a safer alternative to using the cut operator, which would look like this:
parent(A) :- hasChild(A, _), !.
This has a fairly significant cost: parent/1 will only generate a single valid solution, though it will verify other correct solutions. To wit:
?- parent(X).
X = person1.
Notice it did not suggest person4. However,
?- childless(person4).
true.
This asymmetry is certainly a "code smell" to most any intermediate Prolog programmer such as myself. It's as though Prolog has some sort of amnesia or selective hearing depending on the query. This is no way to get invited to high society events!
I would suggest that the best solution here (which handles the mineral/vegetable problem above as well) is to add some more facts about people. After all, a person exists before they have kids (or do they?) so they are not "defined" by that relationship. But continuing to play the game, you may be able to circumvent the problem using setof/3 to construct a list of all the people:
parent(Person) :-
setof(X, C^hasChild(X, C), People),
member(Person, People).
The odd expression C^hasChild(X, C) tells Prolog that C is a free variable; this ensures that we get the set of all things in the first argument of hasChild/2 bound to the list People. This is not first-order logic anymore folks! And the advantage here is that member/2 will generate for us as well as check:
?- parent(person4).
true.
?- parent(X).
X = person1 ;
X = person4.
Is this efficient? No. Is it smart? Probably not. Is it a solution to your question that also generates? Yes, it seems to be. Well, one out of three ain't bad. :)
As a final remark, some Prolog implementations treat not/1 as an alias for \+/1; if you happen to be using one of them, I recommend you not mistake compatibility with pre-ISO conventions for a jovial tolerance for variety: correct the spelling of not(X) to \+ X. :)
Here's another way you could do it!
Define everything you know for a fact as a Prolog fact, no matter if it is positive or negative.
In your sample, we define "positives" like person/1 and "negatives" like childless/1. Of course, we also define the predicates child_of/2, male/1, female/1, spouse_husband/2, and so on.
Note that we have introduced quite a bit of redundancy into the database.
In return, we got a clearer line of knowns/unknowns without resorting to higher-order constructs.
We need to define the right data consistency constraints:
% There is no person which is neither male nor female.
:- \+ (person(X), \+ (male(X) ; female(X))).
% Nobody is male and female (at once).
:- \+ (male(X), female(X)).
% Nobody is childless and parental (at once).
:- \+ (childless(X), child_of(_,X)).
% There is no person which is neither childless nor parental.
:- \+ (person(X), \+ (childless(X) ; child_of(_,X))).
% There is no child which is not a person.
:- \+ (child_of(X,_), \+ person(X)).
% There is no parent which is not a person.
:- \+ (child_of(_,X), \+ person(X)).
% (...plus, quite likely, a lot more integrity constraints...)
This is just a rough sketch... Depending on your use-cases you could do the modeling differently, e.g. using relations like parental/1 together with suitable integrity constraints. YMMY! HTH

Prolog list membership, multiple results returned

I have a standard procedure for determining membership of a list:
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
What I don't understand is why when I pose the following query:
?- member(a,[a,b]).
The result is
True;
False.
I would have thought that on satisfying the goal using the first rule (as a is the head of the list) True would be returned and that would be the end of if. It seems as if it is then attempting to satisfy the goal using the second rule and failing?
Prolog interpreter is SWI-Prolog.
Let's consider a similar query first: [Edit: Do this without adding your own definition ; member/2 is already defined]
?- member(a,[b,a]).
true.
In this case you get the optimal answer: There is exactly one solution. But when exchanging the elements in the list we get:
?- member(a,[a,b]).
true
; false.
Logically, both are just the affirmation that the query is true.
The reason for the difference is that in the second query the answer true is given immediately upon finding a as element of the list. The remaining list [b] does not contain a fitting element, but this is not yet examined. Only upon request (hitting SPACE or ;) the rest of the list is tried with the result that there is no further solution.
Essentially, this little difference gives you a hint when a computation is completely finished and when there is still some work to do. For simple queries this does not make a difference, but in more complex queries these open alternatives (choicepoints) may accumulate and use up memory.
Older toplevels always asked if you want to see a further solution, even if there was none.
Edit:
The ability to avoid asking for the next answer, if there is none, is extremely dependent on the very implementation details. Even within the same system, and the same program loaded you might get different results. In this case, however, I was using SWI's built-in definition for member/2 whereas you used your own definition, which overwrites the built-in definition.
SWI uses the following definition as built-in which is logically equivalent to yours but makes avoiding unnecessary choice points easier to SWI — but many other systems cannot profit from this:
member(B, [C|A]) :-
member_(A, B, C).
member_(_, A, A).
member_([C|A], B, _) :-
member_(A, B, C).
To make things even more complex: Many Prologs have a different toplevel that does never ask for further answers when the query does not contain a variable. So in those systems (like YAP) you get a wrong impression.
Try the following query to see this:
?- member(X,[1]).
X = 1.
SWI is again able to determine that this is the only answer. But YAP, e.g., is not.
Are you using the ";" operator after the first result then pushing return? I believe this is asking the query to look for more results and as there are none it is coming up as false.
Do you know about Prolog's cut - !?
If you change member(X, [X|_]). to member(X, [X|_]) :- !. Prolog will not try to find another solution after the first one.

Reverse lookup in Prolog? (how do I find everything that is true about X?)

So, let's say I have the following in a Prolog database:
person(john).
person(mary).
happy(john).
It is clear to that if I want to list all people, I can type:
person(X).
But, what if I want to find all the things that are true about john? I cannot do:
X(john).
But the effect I would like is to be able to put in "john" and get back "person" and "happy".
There is clearly another way I could store my information:
is(person, john).
is(person, mary).
is(happy, john).
And then, I can do:
is(X, john).
But I lose some expressiveness here. I really would like to be able to do something like:
X(john).
Any ideas?
Thanks!
Parameterizing a query over predicates (as in finding ∀x over x(...)) is not usually possible natively in PROLOG, as this sort of thing is a second- (or, higher)-order logic operation, whereas PROLOG is based on first-order logic.
There are, however, descriptions of how implementations of higher-order logic functions in PROLOG are possible, at least to a limited extent - there are real uses for such functionality. See The Art Of Prolog, Chapter 16, and Higher-order logic programming in Prolog by Lee Naish.
Hm, from my experience, that's not the typical use case of Prolog. If you want to enumerate all "facts" about John, you would first have to define them as terms, and encode their arity. Then you can use call/N and go down the rabbit hole another notch (from memory with the help of GNU Prolog):
relation(1,person).
relation(2,married).
person(john).
married(john,mary).
? relation(1,X), call(X,john).
X = person
| ?- relation(2,X),call(X,john,Y).
X = married
Y = mary
Note that using call has many interesting issues and potential for runtime errors.
This is an approximation:
all_predicates(Term) :-
current_predicate(_, Pred), %% match Pred to any currently defined predicate
\+ predicate_property(Pred, built_in), %% filter out the built-in predicates
functor(Pred, Name, 1), %% check that Pred has 1 argument and match Name to its name
Goal =.. [Name, Term], %% construct the goal Name(Term)
call(Goal). %% Note that if Pred has side effects, they will happen.

Prolog — symmetrical predicates

I have to simulate family tree in prolog.
And i have problem of symetrical predicates.
Facts:
parent(x,y).
male(x).
female(y).
age(x, number).
Rules:
blood_relation is giving me headache. this is what i have done:
blood_relation(X,Y) :- ancestor(X,Y).
blood_relation(X,Y) :- uncle(X,Y)
; brother(X,Y)
; sister(X,Y)
; (mother(Z,Y),sister(X,Z))
; (father(Z,Y),sister(X,Z))
; (father(Z,Y),brother(X,Z)).
blood_relation(X,Y) :- uncle(X,Z)
, blood_relation(Z,Y).
and I am getting i think satisfactory results(i have double prints - can i fix this), problem is that i want that this relation be symmetrical. It is not now.
blood_relation(johns_father, john):yes
blood_relation(john,johns_father): no
so..is there a way to fix this.
And i need query: All pairs that are not in blood_relation..
Update:
What kinds of relationships is the first statement supposed to satisfy?
blood_relation(X,Y):-blood_relation(X,Y).
sorry..it is a bad copy/paste..it
blood_relation(X,Y):-ancestor(X,Y).
Now fixed above.
here are other rules:
father(X,Y) :-
parent(X,Y),male(X).
mother(X,Y) :-
parent(X,Y),female(X).
brother(X,Y) :-
parent(Z,X),parent(Z,Y),
male(X).
sister(X,Y) :-
parent(Z,X),parent(Z,Y),
female(X).
grandFather(X,Y) :-
parent(Z,Y),parent(X,Z),
male(X).
grandMother(X,Y) :-
parent(Z,Y),
parent(X,Z),female(X).
uncle(X,Y) :-
mother(Z,Y),brother(X,Z).
ancestor(X,Y) :-
ancestor(X,Y).
ancestor(X,Y) :-
parent(X,Z),ancestor(Z,Y).
Mother's brother is in uncle definition. It's kind of strange. I've got rules that I need to implement, and I don't know how I can implement rules besides that. I'm just confused.
Any idea how to make blood_relation symmetric? And not_blood_relation is a new rule. And I need query. This one is really giving me headache. Maybe because relation is written like crap.
And there are no more facts. That's all. All rules, and all facts.
query.. not(blood_relation(X,Y)) doesn't work, and I really don't know why.
For example query:
age(X,Y), Y>18,
not(parent(X,Z)),write(X),nl,fail.
works just fine
The naive solution to making a particular predicate symmetric isn't that far from a decent one. For the sake of generality, let's look at a friendship relation so people don't get tripped up on uncles and the like.
Here are some facts detailing a friendship relation (where, say, the numbers are user ids and the particular ordering of the arguments came from who initiated the friendship).
friends(1,2).
friends(5,2).
friends(7,4).
You'd initially think a rule like "friends(A,B) :- friends(B,A)." would fix things right up, but this leads you to infinite recursion because it tells prolog that if it just swaps the argument one more time it might just work. There is a predicate called "#</2" that tells you whether one term (even a variable) comes before another in the "standard order of terms". The technical meaning isn't all that important here, but what we care about is that for two different terms it is only true for one ordering of them. We can use this to break the infinite recursion!
This single rule will take care of making "friend/2" symmetric.
friends(A,B) :- A #< B, friends(B,A).
As neat as this is, there is an approach way you should take for large projects. Recall that the ordering of the args in my list of facts had some actual meaning (who initiated the friendship). Adding the final rule destroyed future access to this information and, for other people reading the code, hides the symmetric property in a single line of code which is easy to ignore in the face of a block of hard-coded data.
Condsider the industrial-strength solution:
friended(1,2).
friended(5,2).
friended(7,4).
friends(A,B) :- friended(A,B).
friends(A,B) :- friended(B,A).
It is bulkier, but it reads cleanly without using obscure predicates and retains the original information (which you might want again someday in a real application).
--
As for finding pairs that don't have a specific property, make sure you always include some predicate to provide context in your rule when you use negation to look for actual individuals.
potential_enemies(A,B) :- user(A), user(B), \+ friends(A,B).
A bit looks like a homework, isn't it...
One trick which most of beginners of prolog don't think of is list pattern matching. Think of a tree like [a1,[[a2],[b2,[[e3],[f3]]],[c2]]] as in <tree>=[root,[<tree1>,<tree2>,...]]:
%Y is immediate child of X?
child(X,Y,[X|S]) :- member([Y|_],S).
%pick one tree in S and check
child(X,Y,[X|S]) :- member([Z|SS],S),child(Z,Y,[Z|SS]).
%X and Y end up with same root?
sib(X,Y,[R|T]) :- child(R,X,[R|T]), child(R,Y,[R|T]).
I think you can improve upon this like, using pairs as roots, adding genders, giving names to specific relations of members of the tree...
What kinds of relationships is the first statement supposed to satisfy?
blood_relation(X,Y):-blood_relation(X,Y).
That isn't telling you anything that you don't already "know" and is going to cause you recursion headaches. As for the 'no' answer, is looks like you've already gotten all of the answers from the query that you are going to get, and the interpreter is just telling you that there aren't any more.
You really should post more facts, and the definition of uncle/2, and is there a reason why you're not matching a mother's brother, just her sister? You have lots of other issues to work on :-).
For everything that is not a blood relation, try this:
not_blood_relation(X, Y) :- blood_relation(X, Y), !, fail.
not_blood_relation(X, Y).
And ask yourself why it works!

Resources