The meaning of
h <- if( p then q else w).
is strictly logical. The semantics of this rule is the same as:
h <- p, q. h <- ~p, w.
Thus, e.g., the compiler requires that the original program, so expanded must be stratified.
However, if-then-else is implemented directly, i.e., without rewriting the program. Thus it adds efficiency, since p is executed only once.
When there are side effectsi, e.g., in updates, the meaning is no longer the same.
Example: Compare two length measures, expressed in yards and inches.
gt_or_eq(length(Y1,I1), length(Y2, I2)) <- if(Y1 = Y2 then I1 >= I2 else Y1 > Y2).
Note that the syntax of the if-predicate) is the same as that of a predicate.
Omitting the else clause: The abbreviation,
h <- if( p then q ).
is also allowed. Its meaning is
h <- if( p then q else true),
``If exceptions occur, then take corrective action and report the problem, otherwise take normal action.''
report_problems(X) <- if(problem(X) then corrective_action else normal_action).export:report_problem($X) is safe but export:report_problem(X) is not; what do we report when there is no problem? A correct formulation would be:
report_problem(X) <- if(problem(Y) then X = Y, corrective_action else X = "noproblem", normal_action).forces you to write complete specifications.
A common mistake is to write the previous rules as:
report_problem(X) <- if(problem(X) then corrective_action else X = noproblem, normal_action).
This can be re-expressed using negation as follows:
report_problem(X) <- problem(X), corrective_action. report_problem(X) <- ~problem(X), X = noproblem, normal_action.
The error is that a non-existential variable is used before it is bound.
Example: Say that,
our university database contains
facts describing professors and fact describing students.
In fact, say that our toy database contains
only the following facts:
The result of executing this rule is nondeterministic.
It can either give a singleton relation containing eithe of
the following two tuples<
A rule (program) where the rules contain choice goals is called
a choice rule (program).
The semantics of a choice program P can be defined
by transforming into a program with negation, SV(P),
called the stable version of P,
which exhibits a multiplicity of total stable models,
each obeying the FDs defined
by the choice goals.
The use of choice is critical in many applications.
For instance, the following nonrecursive rules can be
used to determine whether there are
more boys than girls in a database
containing the unary relations boy and girl:
Example: Are there more boys than girls in our database?
Example: Computing a spanning tree:
Example: Ordering a domain
Example:The sum of the elements in d(X)
The choice construct is significant for both nondeterministic
and deterministic queries. A nondeterministic query is one
where any answer out of a set is acceptable. This is,
for instance, in the previous example where
an advisor ws assigned to a student.
The use of choice to
compute a deterministic query is illustrated by
the sum example: the sum of the elements of a set
is independent from the order in which these are visited.
Nondeterministic Reasoning: Choice
The set-oriented semantics of logic programs lead
to the generation of all answers satisfying a
given set of rules. In many pratical situations,
there is the need for picking an element out of
of a set of candidate in nondeterministic fashion.
Interesting enough, choosing an element, can be
viewed as enforcing a functional dependency
constraint.
student('Jim Black', ee, senior).
professor('Ohm', ee).
professor('Bell', ee).
Now, the rule is that the major of a student must match his/her
advisor's major area of specialization.
Then eligible advisors can be computed as
follows:
eligadv(S, P) <- student(S, Major,Year),
professor(P,Major).
This yields:
elig_adv('Jim Black', 'Ohm')
elig_adv('Jim Black', 'Bell')
But, since a student can only have one advisor,
choice goal will be used
to force the selection of a unique advisor, out of
the eligible advisors, for a student. Thus we
obtain the following choice rule:
actualadv(S, P) <- student(S, Major, Levl),
professor(P, Major), choice((S),(P)).
The goal can also be viewed as
enforcing a functional dependency (FD) ;
thus, in , the second column (professor name) is
functionally dependent on the first one (student
name).
elig_adv('Jim Black','Ohm'), elig_adv('Jim Black','Bell')
match(Bname, Gname) <- boy(Bname ), girl(Gname).
choice ((Bname),(Gname)),
choice ((Gname), (Bname)) .
matchedboy(Bname) <- match(Bname, Gname).
moreboys <- boy(Bname), ~matchedboy(Bname).
The most significant applications of choice involve the use
of choice in recursive predicates. For instance,
the following program computes the spanning tree, starting from
the source node , for a graph where an arc from node a to
node b is
represented by the database fact g(a,b):
st(root,a).
st(X,Y)<- st(,X), g(X,Y), Y ~= a, choice((Y),(X)).
In this example, the goal
ensures that, in , the end-node for the arc produced by the exit rule
has an in-degree of one; likewise,
the goal ensures that the end-nodes for the arcs
generated by the recursive rule have an in-degree of one.
ordered-d(root,root).
ordered-d(X,Y) <- orderedd(_, X), d(Y),
choice((X),(Y)), choice((Y),(X)).
sumd(root, root, 0) <- d(_).
sumd(X, Y, SY) <- sumd(, X, SX), d(Y),
choice((X),(Y)), choice((Y),(X)),
SY=SX+Y.
totald(Sum) <- sumd(_, X, Sum), ~sumd(X, _ , _).
If we eliminate the choice goal from this program
obtain a program that is stratified with respect to negation.
Stratified choice programs always have stable models
Moreover, these stable models
can be computed by strata, as any other stratified program.