39
Prolog for Linguists Symbolic Systems 139P/239P John Dowding Week 10, December 3, 2001 [email protected]

Prolog for Linguists Symbolic Systems 139P/239P John Dowding Week 10, December 3, 2001 [email protected]

Embed Size (px)

Citation preview

Prolog for LinguistsSymbolic Systems 139P/239P

John Dowding

Week 10, December 3, 2001

[email protected]

Iterative Deepening

Addresses depth-first run-away Or exploring an infinite part of the search tree first

If the program has a solution, ID will help you find it

Puts a depth bound on the computation

Increases depth bound when no solutions are found

Iterative Deepening Pure Prolog Interpreter

We can solve this in a general way by writing a specialized Prolog interpreter in Prolog.Using a new Prolog built-in clause/2: clause(Goal, Body)

When (Goal :- Body) is in the Prolog database,and is declared dynamic.

The Body for a fact is defined to be true.

For now, we will only worry about interpreting pure Prolog, no Prolog built-ins or cut.

id_call/[1,3]

id_call(Goal):-start(Start),increment(Increment),id_call(Goal, Start, Increment).

id_call(Goal, Bound, Increment):-retractall(more_search),id_interpret(Goal, Bound, Remaining),Remaining < Increment.

id_call(Goal, Bound, Increment):-more_search,NextBound is Bound + Increment,id_call(Goal, NextBound, Increment).

id_interpret/3

id_interpret(_Goal, 0, _Remaining):-!,assert_once(more_search),fail.

id_interpret(true, Bound, Remaining):-!,Remaining is Bound - 1.

id_interpret((Goal1,Goal2), Bound, Remaining):-!,Bound1 is Bound - 1,id_interpret(Goal1, Bound1, Bound2),id_interpret(Goal2, Bound2, Remaining).

id_interpret(Goal, Bound, Remaining):-NextBound is Bound - 1,clause(Goal, Body),id_interpret(Body, NextBound, Remaining).

Iterative Deepening Translator

Turn something like this:

Into something like this:

Iterative Deepening Translator

Turn something like this:

is_number(0).

is_number(s(Number)):-

is_number(Number).

Into something like this:

is_number(_, 0, _):-

!,

assert_once(more_search),

fail.

is_number(0, Bound, RestBound):-

RestBound is Bound – 1.

is_number(s(Number), Bound, RestBound):-

NextBound is Bound – 1,

is_number(Number, NextBound, RestBound).

Iterative Deepening Translator (cont)

id_consult_term((NT --> Rule)):-!,grammar_rule_body(Rule, Body, Start, End),make_nonterminal(NT, Start, End, Goal),id_consult_term((Goal :- Body)).

id_consult_term((:- Goal)):-!,call(Goal).

id_consult_term((Goal :- Body)):-!,id_add_base_clause(Goal),make_id_goal(Goal, NewGoal, Bound, RemainingBound),id_consult_body(Body, NewBody, NextBound, RemainingBound),assertz((NewGoal :- (NextBound is Bound - 1, NewBody))).

id_consult_term(Fact):-id_add_base_clause(Fact),make_id_goal(Fact, NewGoal, Bound, RemainingBound),assertz((NewGoal :- (RemainingBound is Bound - 1))).

Iterative Deepening Translator (cont)

id_consult_body((Body1, Body2), (NewBody1,NewBody2), Bound, RemainingBound):-

!,

id_consult_body(Body1, NewBody1, Bound, NextBound),

id_consult_body(Body2, NewBody2, NextBound, RemainingBound).

id_consult_body(Goal, NewGoal, Bound, Remaining):-

make_id_goal(Goal, NewGoal, Bound, Remaining).

id_add_base_clause/1

id_add_base_clause(Goal):-

functor(Goal, Functor, Arity),

NewArity is Arity + 2,

functor(BaseGoal, Functor, NewArity),

BoundArg is Arity + 1,

arg(BoundArg, BaseGoal, 0),

BaseBody = (!, assert_once(more_search), fail),

\+ clause(BaseGoal, BaseBody),

!,

asserta((BaseGoal :- BaseBody)).

id_add_base_clause(_Goal).

make_id_goal/4

make_id_goal(Goal, NewGoal, Bound, Remaining):-functor(Goal, Functor, Arity),NewArity is Arity + 2,functor(NewGoal, Functor, NewArity),BoundArg is Arity + 1,arg(BoundArg, NewGoal, Bound),arg(NewArity , NewGoal, Remaining),copy_n_args(Arity, Goal, NewGoal).

copy_n_args(0, _Goal, _NewGoal):-!.

copy_n_args(Index, Goal, NewGoal):-arg(Index, Goal, Arg),arg(Index, NewGoal, Arg),NextIndex is Index - 1,copy_n_args(NextIndex, Goal, NewGoal).

Could have just used make_nonterminal/4

Missed opportunity for generalization…

% this is the lazy way to do this using univ.

make_nonterminal(NT, Start, End, Goal):-

NT =.. List,

append(List, [Start,End], FullList),

Goal =.. FullList.

id_call/1

id_call(Goal):-start(Start),increment(Increment),make_id_goal(Goal, NewGoal, Bound, Remaining),id_call(NewGoal, Start, Bound, Remaining, Increment).

id_call(Goal, Bound, Bound, Remaining, Increment):-retractall(more_search),call(Goal),Remaining < Increment.

id_call(Goal, CurrentBound, Bound, Remaining, Increment):-more_search,NextBound is CurrentBound + Increment,id_call(Goal, NextBound, Bound, Remaining, Increment).

Logic and Prolog

Review Propositional and Predicate Logic

Introduce Clausal Form

Resolution Rule and Theorem Proving

This material is from Ch. 10 in Clocksin and Mellish

Clausal Form and Prolog

(A1 A2 … An) :- (B1 B2 … Bm)

Prolog is restricted to clauses where N <= 1. That is, Prolog cannot prove disjunctions

When M=0, we call this a fact.When N=0, we call this a goal.If M=0 and N=0, we have an empty clause, which is false.The restriction to definite clauses means Prolog cannot represent all first order theories. But, definite clauses are still powerful enough to prove theorems about all computable functions.

Prolog and Theorem Proving

Suppose that we want to prove that a formula B is a logical consequence of a consistent set of clauses S: S = {A1 … AN}

Then, adding B to S should make it inconsistentS’= {A1 … AN, :- B}

This is how Prolog proves theorems, it adds the negation of the Goal to the set of clauses, and proves that it is inconsistent.

Resolution Rule for Predicate Logic

A1 …Ai AN A B1 … BN Ai’

(A1 … B1 … BN … AN A)

If Ai unifies with Ai’, yielding the substitution function

Prolog Theorem Proving

Prolog uses a restricted form of the Resolution Rule as it’s only inference ruleStarting with a Goal (a disjunction of negative literals):- B1 … BN

One application of the resolution rule to the left-most negative literal, and a rule of the formB1’ :- C1 … CM, where B1 unifies with B1’, with substitution

Yields:- (C1 … CM B2 … BN)

This continues until the the empty clause (false) is derivedThe history of substitution functions is used to produce an “answer”, effectively a counter-example to the claim that B1 … BN is inconsistent.

DCG with yes/no and wh- questions

Yes/no questions feature AUX-inversionDoes John like Molly?

The AUX (do, be, can, have, will, etc.) moves before the subject, but still has to agree in number and person:Does he like Molly?

Do you like Molly?

Do they like Molly?

Does the woman like Molly?

Do the women like Molly?

We will add a force marker (decl, ynq, whq) to our QLFs.

Yes/no Questions

s_base(GapsIn, GapsOut, [decl, QLF]) --> declarative_sentence(GapsIn, GapsOut, QLF).

s_base(GapsIn, GapsOut, [ynq, QLF]) -->yes_no_question(GapsIn, GapsOut, QLF).

yes_no_question(GapsIn, GapsOut, QLF) -->aux(Person, Number, _Tense),np(nom, Person, Number, GapsIn, GapsNext, NP, NPVar),vp(_, _, GapsNext, GapsOut, NPVar, VP),{conjoin(NP, VP, QLF)}.

Wh-question

One way to analyse wh-questions is as a wh-noun phrase followed by a sentence containing a gap:Who likes Molly?

Who does Molly like?

English requires the AUX to be inserted for non-subject gaps:Who likes Molly?

Who does Molly like?

*Who Molly likes?

Wh-questions

wh_question(GapsIn, GapsOut, QLF) -->wh_np(Person, Number, NP, NPVar),yes_no_question([np_gap(_Case, Person, Number, NPVar)|GapsIn], GapsOut, YNQQLF),{conjoin(NP, YNQQLF, QLF)}.

wh_question(GapsIn, GapsOut, QLF) -->wh_np(Person, Number, NP, NPVar),declarative_sentence([np_gap(nom, Person, Number, NPVar)|GapsIn], GapsOut, DeclQLF),{conjoin(NP, DeclQLF, QLF)}.

Wh-NPs (cont)

I got lazy on the different forms of wh- NPs

wh_np(third, singular, qterm(wh, NPVar, who), NPVar) -->

[who].

wh_np(third, singular, qterm(wh, NPVar, what), NPVar) -->

[what].

Other things to talk about?

Any other questions?

Prolog compilation

1st argument indexing

Prolog Modules

Prolog Libraries

Or, if-then, if-then-else

statistics[0,2], and how to time things

Prolog compilation

Modern Prolog implementions use the Warren Abstract Machine (WAM) Invented by David Warren, one of the founders of Quintus

Combines to a portable byte-code, which is then interpreted

Some implementations (like sometimes SICStus) compile down to native code.

All modern Prolog implementations support first-argument indexing.

1st Argument indexing

Prolog treats the 1st argument to a predicate specially

Uses the functor, and arity of the 1st argument term to index the predicate

If you are expecting a particular argument position to be an input position,

And that argument differentiates the clauses of the predicates,

Then make that the 1st argument

1st Argument Indexing

Consider:list_length([], 0).list_length([_Head|Tail], N):-

list_length(Tail, PartialN),N is N + 1.And,

member(Element, [Element|_List]).member(Element, [_Head|List]):-

member(Element, List).

1st Argument Indexing (cont)

n(bed, singular, bed(X), X).n(beds, plural, bed(X), X).n(book, singular, book(X), X).n(books, plural, book(X), X).n(cat, singular, cat(X), X).n(cats, plural, cat(X), X).n(desk, singular, desk(X), X).n(desks, plural, desk(X), X).n(dog, singular, dog(X), X).n(dogs, plural, dog(X), X).

Prolog Modules

Keeps Prolog predicates in separate name spaces

File based

Optional

By default, predicates are in the module user.

Directives to define a module::- module(ModuleName, PredicateList).

defines a Module with a set of Public predicates

Directives to access predicates from another module::- use_module(ModuleName).

:- use_module(ModuleName, [Pred1/Arity1, …, PredN/ArityN]).

Modularized Tokenizer

Add to the top of tokenizer.pl (before any predicates):

:- module(tokenizer, [tokenize_file/2, tokenize/2]).

To use it in grammar.pl:

:- use_module(tokenizer, [tokenize/2]).

Prolog Libraries

Prolog has a large set of library predictes

All are defined using the Module system

The libraries are not defined in the Prolog library, and will vary significantly between Prolog versions

So, using libraries will make your Program less portable

Access a library with use_module:- use_module(library(ModuleName)).

:- use_module(library(ModuleName), PredicateList).

Using library(lists)

At the top of assignment.pl:

:- use_module(library(lists),[append/3]).

Special Syntax: or

Or uses the syntax (Goal1 ; Goal2) and creates a new choice point.Defined as though:(Goal1 ; _Goal2) :- call(Goal1).(_Goal1 ; Goal2):- call(Goal2).

Except that cuts in Goal1 or Goal2 are transparent through the ;/2.

Use these carefully because they can make your programs hard to read and understand.

Special Syntax: if-then

If-then uses the special syntax (Condition -> Goal)

Defined as though:(Condition -> Goal) :- call(Condition), !, call(Goal).

Except that any cuts in Condition or Goal are transparent through ->/2.

This is sometimes used for it’s little cut of any choice points in the Condition (called a snip).

This is not logical if-then, since if Condition fails, then (Condition ->Goal) fails.

Special Syntax: if-then-else

If-then-else uses the special syntax:(Condition -> Goal1; Goal2)

Defined as though:(Condition ->Goal1; _Goal2) :-

call(Condition),!,call(Goal1).

(_Condition ->_Goal1; Goal2) :-call(Goal2).

Except that cuts in Condition, Goal1, and Goal2 are transparent through ->/2 and ;/2.

Programming Tips on or, if-then, if-then-else

You never really need them, but they’re handy when your lazy.

They can make your program harder to read and understand.

Use white-space to make the special syntax stand out.( goal1(…)

; goal2(…))

(condition(…) ->

result(…)

; otherwise(…))

Never nest or combine them.

If the Condition contains only built-in predicates, then the compiler can often be clever when compiling them.

Timing and Statistics

Built-in statistics/1 gives lots of information about time and memory use.

statistics/2 gives you information about specific values.

statistics(runtime, [BaseTime, TimeSinceLastCall]).

Times are measured in milliseconds

Timing Predicates

% time(+Goal, +Iterations, -RunTime).time(Goal, Iterations, RunTime):- statistics(runtime, [StartTime, _]), iterate(Iterations, Goal), statistics(runtime, [EndTime, _]), RunTime is (EndTime - StartTime) / Iterations.

iterate(0, _):- !.iterate(Counter, Goal):- call(Goal), !, NextCounter is Counter - 1, iterate(NextCounter, Goal).

Final Projects

Any questions on final projects?

Due date: Dec. ??