Professional Documents
Culture Documents
Logic Programming-1
Logic Programming-1
Logic programming
Rather, the programmer provides a set of facts, a set of rules which can be
applied, and then issues one or more queries.
It is the language engine which is responsible for applying the rules to the set of
facts to derive answers to the query.
For example,
Note that the answers are based only on the available information.
1
The great advantage of a declarative language is that the programmer only needs
to supply the information that is known (facts and rules), and ask questions - NOT
worry about the ways the rules must be applied to answer those questions.
In fact, in Prolog all the queries are expressed like yes/no questions, and the
answers come back either as
o a simple "No" (meaning no way could be found to make the query true),
or
o "Yes", plus all the ways in which the query could be made true.
In the example discussed earlier we might have asked the equivalent of "Is
there an omnivore?" and the answer would have been "Yes, Wilma and
Barney".
Core components
2
o variables: as with more traditional programming languages, we can
declare a variety of variables
properties look like a C++ function call - the name of the property then the
entity that has that property is given in brackets, e.g. carnivore(fred),
or food(vegetables)
relationships in Prolog again look like a C++ function call, we give the
relationship name first, then in brackets the two entities that are related,
e.g. eats(wilma,meat), eats(wilma,vegetables)
For example, a rule could state that if someone eats meat and they eat
vegetables then they are an omnivore.
The "if" symbol: :- which separates the result from the clauses
The clauses: the set of relationships and properties which
determine if the rule is to be applied, this goes on the right hand
side of the rule.
There are several logic symbols which can be used in the right
hand side:
Typically we will enter these into a text file ending with the extension
".pl" (e.g. "flint.pl").
From this point on, everything you type is treated as a query, not a new
fact or rule!.
Example: to repeat our introductory example, we would first create a file (let's
say "flint.pl") containing our list of facts and rules:
eats(fred,meat).
eats(wilma,meat).
eats(betty,vegetables).
eats(wilma,vegetables).
eats(barney,meat).
eats(barney,vegetables).
carnivore(Individual) :- eats(Individual,meat).
omnivore(Individual) :-
eats(Individual,meat),eats(Individual,vegetables).
food(Thing) :- eats(Individual,Thing).
4
Once that is created, we can load the database of facts and rules from the file, then
begin issuing queries and getting answers.
>['flint.pl'].
flint.pl compiled
Yes
>food(meat).
Yes
>carnivore(fred).
Yes
>food(dirt).
No
>omnivore(Individual).
Individual = wilma
Yes
Here we'll just give a very brief explanation-by-example, we'll go into things in
greater detail later.
omnivore(fred).
o search for all the relationships which match the goal, i.e. everything in our
database that begins with omnivore(...)
5
o if we encounter a fact in our database that explicitly states
omnivore(fred). then we can quit and return Yes as soon as we
encountered it.
o if we encounter a rule of the form omnivore(...variable...) :- ...
then we can say fred is an omnivore if we can substiture fred for the
variable (throughout the rule) and still satisfy all the clauses on the right
side of the rule
omnivore(Individual) :-
eats(Individual,meat),eats(Individual,vegetables).
Thus we have two new goals to try to satisfy to check out this rule, and we
begin searching the database for facts and rules beginning with eats(...,
trying to substitute "fred" and "meat" into the rules to continue the query.
If we cannot prove eats(fred,meat) then that clause fails, and hence the
rule fails as well, so we must continue on checking for other facts/rules
defining omnivores.
Observe again that a "No" result doesn't mean something isn't true, it only means
that it cannot be proved from the given set of facts and rules.
For instance, the clause not(X = Y) is satisfied if from the database we cannot
prove X and Y are the same thing.
That is a very different thing from saying X and Y are actually different.
parent(bill,jake).
parent(bill,shelley).
sibling(X,Y) :- parent(M,X),parent(M,Y).
6
This causes a problem if we look for a pair of siblings with the query
sibling(A,B).
o the sibling rule is found, and substituting A,B for X,Y we come up with
the new pair of goals parent(M,A) and parent(M,B)
o In trying to satisfy the first goal, we hit parent(bill,jake), and as a
result try substituting bill for M and jake for A.
o Now we try to satisfy the second goal with this substitution, i.e.
parent(bill,B)
o In trying to satisfy this goal, we again hit parent(bill,jake), and
substitute jake for B
o We have now satisfied both goals using bill,jake,jake for M,A,B
respectively
o Since our goals are all satisfied, we respond with our final answer
o A = jake
o B = jake
o Yes
A logical way to avoid this situation is to use the NOT operator, to specify that
two entities are siblings if they have the same parent but are not (provably) the
same entity
sibling(X,Y) :- parent(M,X),parent(M,Y).
Predicate Calculus
Propositions are essentially logical statements which may be either true or false.
A is B if C is true
if C is true then A is B
if A is not B then C is not true
etc
7
As a result, logic programming languages such as Prolog are based upon a restricted
version of predicate calculus
The goal of a language designer being to pick a restricted version which still allows
expression of all logical possibilities yet is easily implemented
Terminology:(informal)
The most noteworthy attribute of constants is that they are distinguishable one
from another
A variable, much as with variables in other languages, can be assigned the value
of different entities
A compound term consists of a functor (the name or symbol representing a
function or relation) and an ordered list of parameters
An atomic proposition is a proposition which consists of a set of compound
terms
A compound proposition consists of two or more atomic propositions
Propositions can be stated in one of two modes: either as a statement of fact or as
a query
A Horn clause is a proposition in the following form: either
o A single atomic proposition (e.g. brown(dirt)), or
o A single atomic proposition on the left-hand-side of the clause, followed
by the if symbol followed by the logical AND of one or more atomic
propositions on the right hand side, e.g.:
8
They are unlike more traditional variables in that if a variable has been
instantiated you cannot explicitly assign a new value. Thus statements like
X is X + 1 are not valid.
Note that we can use the structure to describe/define data types and
manipulate them.
>origin(point(0,0)).
Yes
>origin(point(1,1)).
No
>origin(0,0).
No
>near_origin(point(1,1),1).
No
>near_origin(point(1,1),2).
Yes
>distance(point(3,4),D).
D = 5
Yes
>near_origin(point(1,1),R).
WARNING: Arguments not instantiated
(Note the last query cannot be handled, as it tries to use the uninstantiated
variable Radius in evaluating the expression X*X+Y*Y < Radius*Radius)
9
Bindings: both values and types are dynamically bound to variables in Prolog.
The temporary binding of values is referred to as instantiation, and takes place
only during the resolution process.
Unification
Unification in Prolog is the matching of values, and can be carried out either explicitly: X
= Y. or implicitly through parameters.
Suppose our knowledge base contains the fact even(X) :- divides(2, X).,
and we issue the query divides(Y).
Two values containing variables can be unified if the constituent variables can
also be unified to values that make the two values the same. E.g.:
lesser(3, Num1) = lesser(Num2, bignumber(X)).
% if we unify 3 = Num2
% and Num1 = bignumber(X),
% we would have lesser(3, bignumber(X)) = lesser(3,
bignumber(X))
% so the statements really can be unified
f(X, b)
f(c, D)
---------------------
Difference: <X,c>, <b,D>
10
In each of these two cases, unification is allowable, giving f(c,b)
Resolution is the process used to try to carry out unification during a Prolog query, and
instantiation takes place as a direct result.
Resolution examples
As discussed earlier, resolution is the process of trying to apply facts and rules from the
knowledge database to try and prove the truth of a query.
If resolution fails to prove a query is true, then the query is said to fail.
To respond to the query, Prolog searches through the knowledge base for a fact or
rule which can tell us if it is cloudy today.
Facts and rules are considered in the same order as they appear in the knowledge
base.
In this case, the first rule encountered tells us directly that cloudy(today) is true,
so a response of Yes is generated.
Again we search through the database, but this time we encounter a rule for
cloudy rather than a directly applicable fact.
We now have a new goal, if we can prove rainy(today) then we have satisfied
the necessary conditions for cloudy(today) to be true.
A new search of the knowledge base begins, looking for facts or rules to prove
rainy(today)
In this case, the second fact examined specifies that, yes, today is rainy.
11
Thus our "subgoal" is satisfied, and (consequently) our original goal is also
satisfied, and a response of Yes can be generated to the query.
In this case, the first applicable rule (i.e. that has cloudy as a head and one
parameter) is cloudy(Day) :- rainy(Day).
Because Day is a variable, and we are looking for the specific value today, we
can instantiate the variable Day with the value today, giving us the rule
cloudy(today) :- rainy(today).
>>From this point the process continues exactly as in the previous example, i.e.
try to satisfy subgoal rainy(today) and succeed because of the applicable fact in
the knowledge base.
Now let's make the query cloudy(tomorrow) to see what happens when a query
fails.
cloudy(tomorrow) :- rainy(tomorrow).
We now search the knowledge base for facts or rules to prove our subgoal,
rainy(tomorrow).
No such facts or rules can be found in the database, so our subgoal fails, and
hence this rule fails to apply.
No other applicable facts or rules can be found in the knowledge base, so our
query as a whole also fails.
Design decisions
12
In what order should you consider the facts and rules in the knowledge base?
In a "pure" logic programming language, the programmer would only have to list
the available facts and rules -- without any regard to the order they are listed in.
It should be the up to the system to apply the facts and rules in an appropriate
order.
Unfortunately, this would make implementation of the system very difficult, and a
much simpler implementation can be attained if the system simply considers facts
and rules in the order in which they are presented.
This creates problems for the programmer, however. Consider the following
knowledge base:
Because the knowledge base contents are searched in order for every goal, the
following happens:
o we try to apply the rule first, i.e. unify 1 with N and 1 with FactorialN,
giving the rule
o factorial(1,1) :- A is 1-1, B is 1/1, factorial(A,B)
o when A and B are evaluated, this gives us a new subgoal of
factorial(0,1).
o when we try to prove this subgoal, we again find the rule first and try to
apply that, giving
o factorial(0,1) :- A is 0-1, B is 1/0, factorial(A,B).
o As you can see, we clearly are not obtaining the desired results
If we simply reverse the order within the knowledge base the query will work:
factorial(1,1).
factorial(N,FactorialN) :- A is N-1, B is FactorialN/N,
factorial(A,B).
Another issue is that in Prolog each time we begin processing a new subgoal we
start searching the knowledge base from the beginning.
13
Suppose we have a knowledge base with thousands of facts, and very near the end
are two facts that are critical to many queries.
Each time we need to apply either of those two facts we must first search the
entire knowledge base first, trying (unsuccessfully presumably) to apply any facts
or rules headed with the same functor.
Thus the Prolog programmer has to be very careful about the order of facts and
rules in the knowledge base to ensure that queries are handled correctly and
efficiently.
o Forward chaining starts with the set of available facts, and begins
applying rules to these with the hope of working "forward" to ultimately
arrive at the desired goal.
Forward chaining works well when the number of possible ways to answer
a query is relatively large (giving you a greater chance of quickly working
forward to a establish a match).
When rules are applied, in what order should you consider the subgoals, and
their subgoals, etc...?
As with the ordering for facts and rules, in a "pure" logic programming language
the order in which goals are evaluated should not be a concern of the programmer.
A :- B,C,D.
14
In Prolog, they are simply handled in left-to-right order.
Picture our set of goals and the subgoals they depend upon as a tree of
possibilities:
A
/|\
/ | \
B C D
/|\ \ |\
E F G H I J
Do we fully explore one subtree first (depth-first), or try and explore the tree level
by level (breadth-first)?
Which search is faster depends on the answer and the tree - at what point(s) in the
tree do we identify the success/failure of subgoals and the overall goal, and how
much of the tree does each approach search before reaching the key point(s).
15
LAB Exercise
parent_of(peter,bob).
parent_of(tom,bob).
parent_of(tom,liz).
parent_of(bob,ann).
parent_of(bob,pet).
parent_of(pet,jim).
male(peter).
male(tom).
male(jim).
male(bob).
female(ann).
female(liz).
female(pet).
father_of(X,Y):-Parent_of(x,y), male(X).
mother_of(X,Y):-Parent_of(x,y), female(X).
grandfather(X,Y):-parent_of(X,Z),parent_of(Z,Y),male(Z).
grandmother(X,Y):-parent_of(X,Z),parent_of(Z,Y),female(Z).
sister_of(X,Y):-parent_of(Z,X),,parent_of(Z,Y), female(X).
brother_of(X,Y):-parent_of(Z,X),,parent_of(Z,Y), male(X).
Query the following and see the whether you can get the required results
father_of(X,Y.
mother_of(X,Y.
grandfather(X,Y).
grandmother(X,Y).
sister_of(X,Y).
16
brother_of(X,Y).
17