Related
So I am currently learning prolog and I can't get my head around how this language works.
"It tries all the possible solutions until it finds one, if it doesn't it returns false" is what I've read that this language does. You just Describe the solution and it finds it for you
With that in mind, I am trying to solve the 8 queens problem ( how to place 8 queens on a chess board without anyone threatening the others).
I have this predicate, 'safe' that gets a list of pairs, the positions of all the queens and succeeds when they are not threatening each other.
When I enter in the terminal
?- safe([(1,2),(3,5)]).
true ?
| ?- safe([(1,3),(1,7)]).
no
| ?- safe([(2,2),(3,3)]).
no
| ?- safe([(2,2),(3,4),(8,7)]).
true ?
it recognizes the correct from the wrong answers, so it knows if something is a possible solution
BUT
when I enter
| ?- safe(L).
L = [] ? ;
L = [_] ? ;
it gives me the default answers, even though it recognizes a solution for 2 queens when I enter them.
here is my code
threatens((_,Row),(_,Row)).
threatens((Column,_),(Column,_)).
threatens((Column1,Row1),(Column2,Row2)) :-
Diff1 is Column1 - Row1,
Diff2 is Column2 - Row2,
abs(Diff1) =:= abs(Diff2).
safe([]).
safe([_]).
safe([A,B|T]) :-
\+ threatens(A,B),
safe([A|T]),
safe(T).
One solution I found to the problem is to create predicates 'position' and modify the 'safe' one
possition((0,0)).
possition((1,0)).
...
...
possition((6,7)).
possition((7,7)).
safe([A,B|T]) :-
possition(A),
possition(B),
\+ threatens(A,B),
safe([A|T]),
safe(T).
safe(L,X):-
length(L,X),
safe(L).
but this is just stupid, as you have to type everything explicitly and really really slow,
even for 6 queens.
My real problem here, is not with the code itself but with prolog, I am trying to think in prolog, But all I read is
Describe how the solution would look like and let it work out what is would be
Well that's what I have been doing but it does not seem to work,
Could somebody point me to some resources that don't teach you the semantics but how to think in prolog
Thank you
but this is just stupid, as you have to type everything explicitly and really really slow, even for 6 queens.
Regarding listing the positions, the two coordinates are independent, so you could write something like:
position((X, Y)) :-
coordinate(X),
coordinate(Y).
coordinate(1).
coordinate(2).
...
coordinate(8).
This is already much less typing. It's even simpler if your Prolog has a between/3 predicate:
coordinate(X) :-
between(1, 8, X).
Regarding the predicate being very slow, this is because you are asking it to do too much duplicate work:
safe([A,B|T]) :-
...
safe([A|T]),
safe(T).
Once you know that [A|T] is safe, T must be safe as well. You can remove the last goal and will get an exponential speedup.
Describe how the solution would look like and let it work out what is
would be
demands that the AI be very strong in general. We are not there yet.
You are on the right track though. Prolog essentially works by enumerating possible solutions and testing them, rejecting those that don't fit the conditions encoded in the program. The skill resides in performing a "good enumeration" (traversing the domain in certain ways, exploiting domain symmetries and overlaps etc) and subsequent "fast rejection" (quickly throwing away whole sectors of the search space as not promising). The basic pattern:
findstuff(X) :- generate(X),test(X).
And evidently the program must first generate X before it can test X, which may not be always evident to beginners.
Logic-wise,
findstuff(X) :- x_fulfills_test_conditions(X),x_fullfills_domain_conditions(X).
which is really another way of writing
findstuff(X) :- test(X),generate(X).
would be the same, but for Prolog, as a concrete implementation, there would be nothing to work with.
That X in the program always stands for a particular value (which may be uninstantiated at a given moment, but becomes more and more instantiated going "to the right"). Unlike in logic, where the X really stands for an unknown object onto which we pile constraints until -ideally- we can resolve X to a set of concrete values by applying a lot of thinking to reformulate constraints.
Which brings us the the approach of "Constraint Logic Programming (over finite domains)", aka CLP(FD) which is far more elegant and nearer what's going on when thinking mathematically or actually doing theorem proving, see here:
https://en.wikipedia.org/wiki/Constraint_logic_programming
and the ECLiPSe logic programming system
http://eclipseclp.org/
and
https://www.metalevel.at/prolog/clpz
https://github.com/triska/clpfd/blob/master/n_queens.pl
N-Queens in Prolog on YouTube. as a must-watch
This is still technically Prolog (in fact, implemented on top of Prolog) but allows you to work on a more abstract level than raw generate-and-test.
Prolog is radically different in its approach to computing.
Arithmetic often is not required at all. But the complexity inherent in a solution to a problem show up in some place, where we control how relevant information are related.
place_queen(I,[I|_],[I|_],[I|_]).
place_queen(I,[_|Cs],[_|Us],[_|Ds]):-place_queen(I,Cs,Us,Ds).
place_queens([],_,_,_).
place_queens([I|Is],Cs,Us,[_|Ds]):-
place_queens(Is,Cs,[_|Us],Ds),
place_queen(I,Cs,Us,Ds).
gen_places([],[]).
gen_places([_|Qs],[_|Ps]):-gen_places(Qs,Ps).
qs(Qs,Ps):-gen_places(Qs,Ps),place_queens(Qs,Ps,_,_).
goal(Ps):-qs([0,1,2,3,4,5,6,7,8,9,10,11],Ps).
No arithmetic at all, columns/rows are encoded in a clever choice of symbols (the numbers indeed are just that, identifiers), diagonals in two additional arguments.
The whole program just requires a (very) small subset of Prolog, namely a pure 2-clauses interpreter.
If you take the time to understand what place_queens/4 does (operationally, maybe, if you have above average attention capabilities), you'll gain a deeper understanding of what (pure) Prolog actually computes.
I've been learning and I came across a problem. I understood the cut operator from the tutorials but I'm trying to solve a problem and I cannot understand the solution.
Problem:
If the car color is red, made in Italy, then it's a Ferrari. If it's red but made in Germany (or any other country. could be more than one), it's Benz. If it's not red and is big, it's ford. If it's not red and not big, it's Toyota.
That is:
red & Italy: Ferrari
red & Germany (or not Italy): Benz
not red & big: ford
not red & not big: Toyota
Given some facts for a particular car object:
color(cx, red).
speed(cx, 220).
make(cx, italy).
type(cx, sport).
I want to write a predicate brand(X, name) that will return the brand of the particular car objects, like:
brand(X, ferrari):-
color(X,red), make(X,T), T=italy.
brand(X, benz) :-
color(X,red), not(make(X,italy)).
brand(X, ford) :-
not(color(X,red)), size(X,big).
brand(X, toyota) :-
not(color(X,red)), not(size(X,big)).
Question is how (and where) do I use the cut operator here so that it doesn't check the same property (eg: here "make") twice? I can't seem to wrap my head around this.
If I check for red and then for make, if the make turns out not italy, how do I write the brand(X, brand_name) for a set of facts for car object "ck" such that it doesn't check the make again? It appears impossible to me.
The short answer: Don't.
Almost invariably, using !/0 will lead to loss of valid solutions.
Always keep in mind that Prolog programs are typically much more general than programs in other languages. In particular, keep in mind that users can always post the most general query, which in your case is:
?- brand(X, Y).
If you have !/0 in this definition, then yes, you will likely "check only once", but on the other hand, you will fail to generate all valid answers.
One good way out is to use if_/3 from library(reif). For example, in your case, you can write the facts as:
color(cx, red, true).
speed(cx, 220, true).
make(cx, italy, true).
type(cx, sport, true).
And now you can write:
car_type(C, Type) :-
if_(color(C,red),
if_(make(C, italy), Type=ferrari, Type=bentz),
if_(type(C, big), Type=ford, Type=toyota)).
Importantly, the most general query will still work even if there are multiple solutions:
?- car_type(C, Type).
C = cx,
Type = ferrari.
I'm trying to use Prolog to solve a simple game in which there are 3 players: Alice, Bob and Charlie. Each player secretly chooses a card to play, where cards can either be red or blue. The cards are then shuffled and turned over.
Assuming Alice's viewpoint, we know which card she played. Therefore if the revealed cards are blue, blue and red, and Alice played red, then she can deduce that both Bob and Charlie played blue. I'm struggling to define the appropriate causes for this. Here are my basic facts:
player(alice).
player(bob).
player(charlie).
color(blue).
color(red).
% The overturned cards -- all players can see these. Order is unimportant.
cards([blue, red, red]).
played(alice, blue).
From this, we should be able to deduce that Bob and Charlie each played red. I'm unsure how to tell Prolog that each of the three players played exactly one of the cards in the cards([blue, red, red]) fact. Or perhaps something along the lines of num_cards(blue, 1), num_cards(red, 2) would be better?
As a slightly more difficult example, it should be possible for the following facts to be used in deducing that Charlie played a red card (for example if Alice was able to peek at the card played by Bob):
player(alice).
player(bob).
player(charlie).
color(blue).
color(red).
% The overturned cards -- all players can see these. Order is unimportant.
cards([blue, red, red]).
played(alice, red).
played(bob, blue).
The most similar SO question I was able to find was this one, but I haven't been able to apply it to my problem. The CLPFD library definitely seems relevant.
Already for a really well-done background search: +1! The question you linked to and Boris's solution is indeed strongly related to this task.
First, I would like to point out that your task looks easy on the surface and is something that prima facie looks suitable for Prolog beginners to tackle. In my view, such tasks are not easy at all, and the difficulty quickly gets out of hand when additional knowledge (such as: who knows what, throughout different layers) must also be represented. I can well imagine that beginners who get such tasks as assignments will quickly walk away with the feeling "I could have easily solved this in Java, but it is impossible in Prolog". The fact that they could not have solved it in Java either usually does not bother them in the slightest.
In this concrete case, clpfd constraints are indeed a great fit. In fact, the global_cardinality/2 constraint which is for example available in SICStus Prolog solves both examples easily.
When using CLP(FD) constraints, the trick is to map your domain of interest to integers. In this case, I will (arbitrarily) use:
1 for blue
2 for red.
Also, I will simply use variables, one for each person, standing for the concrete "card" (i.e., integer) the person played. The idea is to specify what we know, and let the constraint solver figure out the rest.
So we have, in the first case:
?- global_cardinality([Alice,Bob,Charlie], [1-1,2-2]),
Alice = 1.
Alice = 1,
Bob = Charlie, Charlie = 2.
And in the second case:
?- global_cardinality([Alice,Bob,Charlie], [1-1,2-2]),
Alice = 2,
Bob = 1.
Alice = Charlie, Charlie = 2,
Bob = 1.
So in both cases, simply stating the given constraints suffices to deduce the single respective solution, just like you expected.
my hint needs a 'syntactical adaptation' to fit your question: from my viewpoint, it's essential to separate the facts expressing a particular query from entities identities: so, I propose a game/2 assessing the relation between a set of cards (those overturned, of course) and an association of player and played card, expressed as Player-Card:
player(alice).
player(bob).
player(charlie).
color(blue).
color(red).
game(Cs, [P-C|Ps]) :-
player(P), color(C),
select(C, Cs, Other),
game(Other, Ps),
\+ memberchk(P-_, Ps).
game([], []).
now, a lot of specific queries can be answered. For example
game([blue, red, red], [alice-blue,bob-B,charlie-C]).
B = C, C = red ;
B = C, C = red ;
false.
or
?- so:game([blue, red, red], [alice-blue,X,Y]).
X = bob-red,
Y = charlie-red ;
...
or
?- game([blue, red, red], [alice-red, bob-blue, Y]).
Y = charlie-red ;
...
To avoid duplicates solutions, setof/3 can be used.
I've got a little problem and don't know where to find a solution. You probably heard of problem of flying birds:
bird(eagle).
bird(penguin).
can_fly(penguin):-!,fail.
can_fly(X):-bird(X).
I tried to modify and use this knowledge for some "love story". Imagine this
maried(a, b).
maried(c, d).
lovers(a, d).
likes(X, Y):-maried(X, Y).
Now I want to say something like "If X is maried with Y, but X is Z's lover, then X doesn't like Y, but likes Z".
I tried this:
likes(X, Y) :- lovers(X, Y).
likes(X, Y) :- maried(X, Y), lovers(X, _),!,fail.
likes(X, Y) :- maried(X, Y).
It works unless I want to evaluate a goal
likes(A, B).
If there is more facts in the database and Prolog finds first cheater, it will stop backtracking and I can't find any other solution. Maybe it will be obvious after, but now I have nothing on my mind..
Thanks in advance (and maybe sorry for my English :))
Already your first example is not too useful. You can ask:
is the eagle a bird?
is the penguin a bird?
can the eagle fly?
can the penguin fly?
but you can't even ask, "which birds can fly?":
?- can_fly(Bird).
false.
If you would want to be able to ask more general question, like, "which birds can fly?", or "which birds cannot fly?", you would need to either explicitly list the flying or non-flying birds. As most birds can fly, let's list explicitly the non-flying birds:
bird(eagle).
bird(penguin).
bird(ostrich).
bird(dodo).
bird(sparrow).
bird(pigeon).
flightless_bird(penguin).
flightless_bird(ostrich).
flightless_bird(dodo).
bird_of_pray(eagle).
extinct(dodo).
extinct(wooly_mammoth).
can_fly(Bird) :-
bird(Bird),
\+ flightless_bird(Bird).
extinct_bird(Bird) :-
bird(Bird),
extinct(Bird).
Note the use of the ISO predicate for negation, \+/1. It is true if the goal cannot be proven. It is much cleaner than the fail-cut combination you are using.
How you organize your knowledge is a totally different question. The example I have given is incomplete and not necessarily the best way to do it. As a general rule, you should try to keep your data in a normalized form, with facts and clauses of facts playing the role of tables and table rows.
Hopefully this answer points in the right direction.
The cut-fail thing is an antipattern that's misleading you. It would be much better to say something in the original like this:
bird(eagle).
bird(penguin).
flightless(penguin).
can_fly(X) :- bird(X), \+ flightless(X).
See #boris's answer for an excellent and much more detailed discussion of this problem.
So, you have this database. I'm going to put names in so that I can comprehend it a little better.
married(bill, hillary).
married(barack, michelle).
lovers(bill, michelle).
Now what you want to say is that married people like each other, unless they're cheating. Well, it would be better to define these terms in Prolog so we can reason with them. Create the language we need to use to define our domain. That's going to look like this:
cheating(Cheater, SpitedSpouse, Lover) :-
married(Cheater, SpitedSpouse),
lovers(Cheater, Lover),
SpitedSpouse \= Lover.
Now it's much easier to define likes/2!
likes(Husband, Wife) :- married(Husband, Wife), \+ cheating(Husband, Wife, _).
likes(Husband, Lover) :- cheating(Husband, _, Lover).
We can even define dislikes properly:
dislikes(SpitedSpouse, Lover) :- cheating(_, SpitedSpouse, Lover).
dislikes(Cheater, Spouse) :- cheating(Cheater, Spouse, _).
Look at what we've learned: what you really have is a marriage relationship between two people, or a cheating relationship between three people, and of your other predicates are just projections of these two fundamental relationships. That's pretty neat, yeah? :) cheating/3 is basically the classic "love triangle." That suggests ways we could evolve the program to be more potent: handling love quadrilaterals, of course! And so forth.
Notice something interesting? This code can't "catch" michelle—isn't she just as culpable as bill? This underscores a bigger problem: the gender/orientation limitation of the predicates. I think it helps to have concrete nouns like these to see the logical relationships, but it's a dangerous shortcut that should be resolved. An easy way to handle the logic would be to create a predicate like this:
spouse(X, Y) :- married(X, Y)
spouse(X, Y) :- married(Y, X).
Of course you then have to do more checks to make sure you don't have the same people repeated, but it's not hard, and then change your variables to be less gender-specific.
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!