COS 333: Chapter 16, Part 3

Willem van Heerden
16 Sept 202070:15

Summary

TLDRThis lecture delves into logic programming languages, focusing on Prolog's basic elements, including arithmetic operations and list structures. It explores examples of list manipulation and discusses Prolog's limitations, such as resolution order control and the closed world assumption. The session also touches on practical applications of logic programming in databases, expert systems, and natural language processing, providing insights into the real-world uses of these languages.

Takeaways

  • 📚 The lecture discusses Prolog, a logic programming language, and its basic elements, list structures, and real-world applications.
  • 🔢 Prolog supports integer arithmetic operations using the 'is' operator, but avoids floating-point arithmetic due to potential issues in the resolution process.
  • 🚗 The script provides an example of implementing a 'speed' and 'time' relation in Prolog and how to use these to calculate 'distance' with a query.
  • 📝 Lists in Prolog are similar to those in Lisp and Scheme, allowing for nested structures and terminated by an empty list.
  • 🔑 Prolog uses a recursive approach for list processing, requiring careful ordering of base and recursive cases for efficient execution.
  • 🔄 The 'append' and 'reverse' propositions in Prolog are implemented recursively, demonstrating the language's capability for list manipulation.
  • 🚫 Prolog has certain deficiencies, including issues with resolution order control, the closed world assumption, the negation problem, and intrinsic limitations in computations.
  • ✂️ 'Cuts' in Prolog are used to control backtracking and can improve efficiency by preventing unnecessary search steps.
  • 🔍 The 'not' operator in Prolog is used to handle logical negations, but it does not function as a true logical negation due to the closed world assumption.
  • 🔑 Practical applications of logic programming include use in relational database management systems, expert systems, and natural language processing.
  • 📈 The lecture concludes with a discussion on the practical uses of logic programming, highlighting its role in intelligent query systems and AI.

Q & A

  • What is the primary focus of the third lecture on logic programming languages?

    -The primary focus of the third lecture is to conclude the discussion on Prolog, covering topics such as basic elements of Prolog, simple arithmetic operations, list structures, general deficiencies of Prolog, and application areas of logic programming in the real world.

  • Why are floating point values and arithmetic not emphasized in Prolog?

    -Floating point values and arithmetic are not emphasized in Prolog because floating point values often do not represent exact fractional values, which can result in unexpected failures during the matching process performed by resolution.

  • How does Prolog support integer arithmetic?

    -Prolog supports integer arithmetic through the use of the 'is' operator, which has two operands and uses regular infix notation for arithmetic expressions, similar to languages like C++ or Java.

  • What is the significance of the 'is' operator in Prolog?

    -The 'is' operator in Prolog is used to instantiate a variable with the value of an arithmetic expression. It is important to note that the 'is' operator is not an assignment statement and has specific rules about variable instantiation on both its left and right operands.

  • Can you explain the concept of facts and rules in Prolog using the example of speed and time relations?

    -In Prolog, facts are used to define relations with parameters, such as the speed and time of vehicles. For example, facts like 'speed(ford, 100)' and 'time(ford, 20)' define the speed and time relations for a vehicle named 'ford'. Rules, on the other hand, can define more complex relations, like the distance traveled, using variables and other relations.

  • How does Prolog handle list structures?

    -Prolog handles list structures similarly to Lisp and Scheme, allowing for the creation of nested lists containing atoms, atomic propositions, and other terms. Lists are implicitly terminated by an empty list and can be manipulated using head and tail notation.

  • What is the general approach for implementing list processing in Prolog?

    -List processing in Prolog generally requires a recursive approach, working through lists one element at a time. This involves defining base cases and recursive cases as separate Prolog statements, with the base cases often being atomic propositions and the recursive cases being rules.

  • What is the purpose of the underscore character in Prolog?

    -The underscore character in Prolog represents an anonymous variable, indicating that the programmer does not care about the instantiation of that variable during the unification process. It is used to simplify Prolog implementations, particularly in list processing where certain values may not be relevant.

  • Can you provide an example of a Prolog proposition that performs list manipulation?

    -An example of a Prolog proposition that performs list manipulation is the 'member' proposition, which defines a relation between a term and a list. It checks if the term is contained within the list using a recursive strategy with a base case (when the term is the head of the list) and a recursive case (when the term is a member of the tail of the list).

  • What are some of the deficiencies associated with the Prolog programming language?

    -Some of the deficiencies associated with Prolog include resolution order control, the closed world assumption, the negation problem, and intrinsic limitations with certain kinds of computations that Prolog cannot perform efficiently.

  • How does Prolog handle the sorting of lists?

    -Prolog handles the sorting of lists by generating permutations of the original list and checking if each permutation is sorted. This process can be very inefficient as it may require generating every possible permutation of the list to find a sorted version.

  • What are some practical application areas for logic programming languages?

    -Logic programming languages have practical applications in relational database management systems for implementing intelligent query systems, in expert systems for decision making based on a set of rules, and in natural language processing within the domain of artificial intelligence.

Outlines

00:00

📚 Introduction to Prolog and Arithmetic Operations

The lecture delves into the intricacies of logic programming languages, specifically Prolog, by concluding the discussion on Prolog's basic elements. It commences with Prolog's support for simple arithmetic operations, emphasizing integer values and the use of the 'is' operator for expressions. The lecture also addresses the limitations of floating point values due to their potential to cause unexpected failures during the resolution process. The 'is' operator's role in variable instantiation and the distinction between Prolog's treatment of arithmetic and imperative programming languages like C++ or Java are highlighted.

05:01

🚗 Prolog's Data Structures: Relations and Rules

This segment introduces Prolog's list structures and their significance as the lecture's main focus. It presents example propositions akin to list manipulation programs previously discussed in Scheme. The script outlines the creation of relations and rules in Prolog, using the speed and time of vehicles as an example to illustrate how facts and rules interrelate to define complex relations such as distance traveled. The process of querying Prolog to determine instantiations for variables and the resolution process's role in searching for valid matches are explained.

10:02

🔗 List Processing in Prolog

The paragraph explores Prolog's list structures, drawing parallels with Lisp and Scheme, and emphasizing the recursive approach necessary for list processing. It explains the notation for accessing the head and tail of a list and discusses the importance of order in Prolog statements for recursive list processing. The paragraph also introduces the concept of anonymous variables represented by the underscore character for values that are not relevant to the outcome of a Prolog proposition.

15:02

🔄 Recursive List Processing Techniques in Prolog

This section delves deeper into the recursive strategies for list processing in Prolog, illustrating how to implement propositions that perform operations like membership checks and list construction. It explains the member proposition, which determines if a term is part of a list, and the append proposition, which concatenates two lists. The importance of the order of statements and the use of base and recursive cases in implementing these recursive strategies are highlighted.

20:05

🔄 Implementing List Manipulations: Member and Append

The script provides a detailed walkthrough of implementing the 'member' and 'append' propositions in Prolog. It explains how the member proposition checks for the presence of an element within a list using a base and recursive case approach. Similarly, the append proposition is implemented to join two lists, with the process involving recursive elimination of list elements and re-adding them in reverse order. The explanation includes example queries that demonstrate the use of these propositions in Prolog.

25:06

🔄 Advanced List Manipulations: Reverse Proposition

The paragraph discusses the implementation of the reverse proposition in Prolog, which reverses the order of elements in a list. It describes the recursive strategy employed, which involves reversing the tail of the list first and then appending the head of the original list to this reversed tail. The explanation includes the use of the append proposition in achieving the reverse operation and provides example queries that showcase the reverse proposition's utility.

30:07

🚫 Deficiencies in Prolog Programming

This segment identifies and discusses four main deficiencies associated with Prolog programming. These include resolution order control, which affects the efficiency and context independence of Prolog programs; the closed world assumption, which limits Prolog's ability to handle negative responses; the negation problem, which complicates the handling of logical negations; and intrinsic limitations of the resolution process, which make certain computations inefficient. The paragraph provides examples to illustrate these deficiencies and their impact on Prolog's practical use.

35:08

✂️ Resolution Order Control and Cut Operator

The paragraph examines the issue of resolution order control in Prolog and its potential to cause non-terminating recursions. It contrasts two different implementations of the ancestor proposition to demonstrate how the order of rules can affect program execution. The explanation also introduces the cut operator, which allows programmers to control backtracking and improve program efficiency. The use of cuts is illustrated with an example of the 'valid member' proposition, highlighting their role in avoiding unnecessary computational steps.

40:10

🔒 Closed World Assumption and Negation Problem

This section delves into the closed world assumption of Prolog, which states that Prolog can only prove things with provided facts and rules, leading to potential misinterpretations of negative responses. The negation problem is also discussed, illustrating how Prolog's handling of logical negations can result in incorrect outcomes, such as the siblings proposition example. The paragraph explains the limitations of Prolog's 'not' operator and the challenges in establishing true logical negations within the language.

45:11

🔑 Intrinsic Limitations and Practical Applications

The final paragraph addresses the intrinsic limitations of Prolog, such as the inefficient resolution process for tasks like sorting lists, which can require generating all possible permutations. It then shifts focus to practical applications of logic programming languages, including their use in relational database management systems for intelligent query processing, in expert systems for decision-making based on rules, and in natural language processing within artificial intelligence.

Mindmap

Keywords

💡Logic Programming Languages

Logic programming languages are a type of programming paradigm that is primarily based on formal logic. In the context of the video, Prolog (Programming in Logic) is discussed as an example of such a language, where programs are expressed as a set of facts and rules about some problem domain, and computation is performed by deriving new statements from the existing ones through logical inference.

💡Prolog

Prolog is a logic programming language that is central to the video's discussion. It is known for its ability to handle complex queries and symbolic processing. The script delves into the specifics of Prolog's operations, such as arithmetic operations, list structures, and its unique syntax involving variables and predicates.

💡Arithmetic Operations

Arithmetic operations refer to the basic mathematical functions such as addition, subtraction, multiplication, and division. In the video, it is mentioned that Prolog supports simple integer arithmetic operations using the 'is' operator, which is significant for performing calculations and setting values within the program.

💡List Structures

List structures in Prolog represent a fundamental data type, allowing for the organization of elements in a sequence. The script discusses how Prolog lists are similar to those in Lisp and Scheme, and how they can be manipulated using operations such as accessing the head and tail of a list, which are crucial for list processing tasks.

💡Resolution Process

The resolution process in Prolog is the mechanism by which the language deduces new facts from existing ones. It is a form of inference that is used to match goals with program clauses, instantiate variables, and derive solutions to queries. The video explains how this process can be affected by the order of clauses and the instantiation of variables.

💡Variables

Variables in Prolog are used to represent unknown values that can be instantiated during the resolution process. The script explains the distinction between instantiated and non-instantiated variables, particularly in the context of the 'is' operator, where variables on the left side must not be instantiated, and those on the right must be.

💡Instantiation

Instantiation in Prolog refers to the process of assigning a value to a variable. The video describes how variables become instantiated with integer values through arithmetic expressions using the 'is' operator, and how this process is crucial for the functioning of predicates and rules within the language.

💡Rules

Rules in Prolog are used to define relationships between different elements and are a key part of the language's logic. The script provides an example of a rule defining a 'distance' relation, which is derived from the 'speed' and 'time' relations, illustrating how rules can be used to express complex logic.

💡Recursion

Recursion in the context of the video refers to the process of a function calling itself in order to solve a problem by breaking it down into smaller instances of the same problem. The script discusses how recursion is essential for list processing in Prolog, where operations such as 'member', 'append', and 'reverse' are implemented recursively.

💡Deficiencies

The video outlines several deficiencies associated with Prolog, including issues with resolution order control, the closed world assumption, the negation problem, and intrinsic limitations of the resolution process. These deficiencies highlight the challenges and limitations of using Prolog for certain types of computations and practical applications.

💡Practical Applications

The script concludes by discussing practical applications of logic programming, such as in relational database management systems, expert systems, and natural language processing. These applications demonstrate the relevance and utility of logic programming languages like Prolog in various domains of computer science and artificial intelligence.

Highlights

Introduction to the third lecture on logic programming languages, focusing on concluding the discussion on Prolog.

Continuation of the discussion on basic elements of Prolog, starting with support for simple arithmetic operations.

Emphasis on list structures as the main focus of the lecture, with examples of list manipulation programs similar to those in Scheme.

Explanation of general deficiencies in Prolog programming language, affecting its practical usage.

Overview of application areas of logic programming in the real world, such as relational database management systems and expert systems.

Prolog's support for integer values and arithmetic operations, with a detailed explanation of the 'is' operator.

Discussion on the potential issues with floating point values in Prolog and the decision to focus on integer arithmetic.

Illustration of how integer arithmetic can be implemented in Prolog using facts and rules, with an example of a speed and time relation.

Introduction to list structures in Prolog, comparing them to lists in Lisp and Scheme, and explaining list notation and operations.

Explanation of the recursive approach needed for list processing in Prolog, with examples of base and recursive cases.

Discussion on the use of anonymous variables in Prolog to indicate irrelevant values during list processing.

Presentation of example Prolog propositions for list manipulations, including 'member', 'append', and 'reverse'.

Analysis of the deficiencies in Prolog, such as resolution order control and its impact on program efficiency.

Introduction and explanation of the closed world assumption in Prolog and its implications for query results.

Explanation of the negation problem in Prolog, demonstrating the difficulty in handling logical negations with examples.

Discussion on the intrinsic limitations of Prolog's resolution process, particularly in tasks like sorting lists.

Conclusion of the lecture with a summary of the practical applications of logic programming in various fields.

Transcripts

play00:00

this is the third lecture on

play00:03

logic programming languages in which

play00:05

we'll conclude our discussion

play00:07

on prologue

play00:10

these are the topics that we'll be

play00:12

covering in today's lecture

play00:14

we'll continue with our discussion on

play00:16

the basic elements of prologue

play00:18

beginning with prologue support for

play00:21

simple

play00:22

arithmetic operations we'll then move on

play00:25

to

play00:26

list structures which will be the main

play00:28

focus

play00:29

of this lecture and we'll look at

play00:32

a few example propositions which

play00:35

are similar to the example list

play00:38

manipulation programs

play00:40

that we covered when we were looking at

play00:42

scheme in the previous chapter

play00:45

we'll then look at some general

play00:47

deficiencies

play00:48

of the prologue programming language and

play00:51

then

play00:52

finally finish off with a few

play00:54

application areas

play00:56

of logic programming in the real world

play01:01

prolog allows variables to be

play01:03

instantiated with

play01:04

integer values and it also supports

play01:07

simple integer arithmetic miniprolog

play01:11

implementations

play01:12

also support floating point values as

play01:15

well as floating point arithmetic

play01:17

however floating point values can

play01:19

potentially cause a problem during the

play01:22

resolution process

play01:24

this is because floating point values

play01:27

very often do not represent exact

play01:30

fractional values

play01:31

and therefore they can result in

play01:34

unexpected

play01:35

failures during the matching process

play01:37

that is performed by

play01:38

resolution as a result of this we won't

play01:41

be focusing on floating point values

play01:44

or floating point arithmetic any further

play01:47

and we will instead only pay attention

play01:50

to

play01:50

integer values and integer arithmetic

play01:54

so integer arithmetic then is supported

play01:57

by means

play01:58

of the is operator and the is operator

play02:01

has

play02:02

two operands a left operand and a

play02:05

right operand the right operand of the

play02:08

is operator

play02:09

is an arithmetic expression and we

play02:12

use regular infix notation

play02:15

for these arithmetic expressions so in

play02:18

other words the same kind of notation

play02:20

that you would be used to from languages

play02:23

like c

play02:23

plus or java the left operand of the

play02:28

is operator is a variable

play02:32

so over here we have an example of an

play02:34

expression that demonstrates the use

play02:36

of the is operator we can see on the

play02:40

left hand side we have a variable a

play02:43

and on the right hand side we have an

play02:46

arithmetic expression

play02:48

which involves variables so we have the

play02:50

variable

play02:51

b and the value of that variable is

play02:53

divided by

play02:54

17 and then we add the value of the

play02:58

variable

play02:58

c to that result now it's important to

play03:02

understand

play03:03

that all variables on the right hand

play03:06

side of the is operator must be

play03:08

instantiated

play03:10

and variables on the left hand side must

play03:12

not be

play03:13

instantiated then by means of the is

play03:17

operator the variable on the left hand

play03:19

side becomes instantiated

play03:21

and it is instantiated with the value

play03:24

of the expression on the right hand side

play03:28

now these rules then mean

play03:31

that the is operating prologue is

play03:34

not an assignment statement so

play03:38

in other words this kind of expression

play03:40

here is

play03:41

illegal and if we were to try to

play03:44

implement this by means of

play03:46

an assignment in a standard imperative

play03:49

programming language like c

play03:51

plus or java then this kind of

play03:54

assignment would be valid however this

play03:57

is always illegal in prologue

play04:00

because of the sum variable so if we

play04:04

assume then that the sum variable is

play04:06

instantiated with

play04:07

a value then the right

play04:10

hand side is legal

play04:14

however the left hand side is illegal

play04:17

because the variable on the left hand

play04:19

side must not be instantiated

play04:22

conversely if the sum variable

play04:26

has not been instantiated

play04:29

then it means that the left hand side is

play04:32

legal however the right hand side is

play04:35

illegal

play04:36

because all of the variables on the

play04:37

right hand side must be

play04:40

instantiated

play04:43

this is a simple example that

play04:45

illustrates how

play04:46

integer arithmetic can be used in a

play04:48

prologue implementation

play04:50

so over here we have our implementation

play04:53

and

play04:54

this consists of eight facts

play04:57

and a single rule if we look at

play05:01

the first four facts we see that they

play05:04

together define

play05:05

the speed relation and the speed

play05:07

relation

play05:08

has two parameters the first parameter

play05:12

is an atom that specifies a specific

play05:15

vehicle so these vehicles in this

play05:18

example then

play05:19

are ford chevy

play05:22

dodge and volvo notice that they all

play05:26

start with a lower case letter

play05:28

which indicates that they are all atoms

play05:31

then the second parameter of the speed

play05:34

relation

play05:34

is an integer value and this represents

play05:37

the speed

play05:38

associated with a specific vehicle

play05:41

so our first fact then would be read as

play05:43

the speed of the forward

play05:45

is 100 the second fact states that the

play05:48

speed of the chevy

play05:50

is 105 then we have the speed of the

play05:54

dodge

play05:54

is 95 and finally the speed of the volvo

play05:58

is 80. our next four facts together

play06:02

define

play06:03

the time relation and the time relation

play06:05

again

play06:06

has two parameters the first of which

play06:09

is an atom representing a specific

play06:12

vehicle

play06:13

and then the second parameter is an

play06:16

integer value but this time representing

play06:20

the time associated with a specific

play06:22

vehicle

play06:24

so the first time fact would then

play06:27

be read as the time of the forward

play06:30

is 20. next we have the time of

play06:34

the chevy is 21 then the time of the

play06:37

dodge

play06:38

is 24 and finally the time of the volvo

play06:42

is also 24. so now we can move on

play06:45

to our rule and this rule

play06:48

defines the distance relation which once

play06:52

again

play06:52

has two parameters the first parameter

play06:56

represented by the variable x over here

play06:59

is an atom that represents a specific

play07:02

vehicle

play07:03

and the second parameter y will be

play07:06

an integer value that represents the

play07:09

distance

play07:10

traveled by a specific vehicle so

play07:13

what are we specifying by means of this

play07:16

rule

play07:17

we are stating that y

play07:20

is the distance traveled by a specific

play07:23

vehicle

play07:23

x if the speed of x

play07:28

is defined by the variable

play07:31

speed and the time of x

play07:35

is defined by the variable time

play07:39

notice that speed and time in both cases

play07:42

here

play07:42

are variables because they start with

play07:44

uppercase letters

play07:46

so then we finally have

play07:49

the distance traveled by x which is

play07:52

y as we see over here and y

play07:56

then is defined as the variable speed

play07:59

multiplied by the variable time

play08:02

so now let's look at how this

play08:06

distance rule would be used

play08:09

we're assuming that we issue this

play08:12

query to the prolog system in query mode

play08:16

so we specify then the distance by means

play08:20

of the relation

play08:22

our first parameter is the atom chevy

play08:25

and then we are specifying the second

play08:28

parameter

play08:29

as a variable x now it's important to

play08:32

note that this variable

play08:33

x in the query does not relate to

play08:36

the x used in the rule over here

play08:40

these are two independent variables

play08:43

so what we are then essentially asking

play08:45

prolog to do

play08:46

by means of this query is determine an

play08:49

instantiation for the variable x

play08:52

such that that instantiation then

play08:55

defines the distance

play08:56

traveled by the chevy

play08:59

so let's look then at the series of

play09:01

instantiations that are performed

play09:04

well first of all we look at our query

play09:08

because recall that prolog works from

play09:11

the query

play09:12

to a fact or set of facts

play09:16

that make the query true so

play09:19

we see then that we reach our

play09:23

rule with the consequent over here

play09:26

and therefore we use the atom

play09:29

chevy to instantiate the variable x

play09:32

over here so then we move

play09:36

on to the antecedent of our rule

play09:39

and we start off then with this speed

play09:42

relation over here

play09:44

well we see that we've instantiated x

play09:47

to the atom chevy in this case so x here

play09:51

then gets instantiated

play09:52

to chevy so this is then our first

play09:56

proper instantiation so

play09:59

now we have our variable speed at this

play10:02

point so now prolog needs to determine

play10:04

what a valid instantiation is for this

play10:08

variable

play10:09

so prolog then begins searching from the

play10:12

top of the program down towards the

play10:14

bottom

play10:15

and it then finds this

play10:18

fact over here that specifies that we

play10:22

have the speed of the chevy

play10:23

which is 105. so this then results

play10:27

in the speed variable being instantiated

play10:31

with a value of

play10:33

105. so now we can move

play10:36

on to the next relation within

play10:40

our antecedent and now we are trying to

play10:43

find the time

play10:44

for x and again we've instantiated

play10:47

x to chevy so again we start then

play10:51

searching from the top

play10:52

of the program and we find

play10:55

the fact over here that specifies the

play11:00

time of the chevy so

play11:03

this then results in 21

play11:07

being the instantiation for the variable

play11:10

time

play11:10

over here so time then gets instantiated

play11:13

to

play11:14

a value of 21. finally

play11:17

we then have our last term over here

play11:21

which then creates an instantiation for

play11:23

the variable

play11:24

y so we have instantiated then speed

play11:28

and time as we've previously seen speed

play11:30

has been instantiated

play11:31

to 105 and time has been instantiated

play11:35

to 21. so the result then of this

play11:38

multiplication

play11:40

is 105 multiplied by 21 which gives us a

play11:43

result

play11:43

of 2205

play11:47

and that then is the value that is used

play11:50

to instantiate

play11:51

our variable y so

play11:54

now prolog has found an instantiation

play11:58

for y in this case which is the second

play12:02

parameter of

play12:03

our distance relation which means that

play12:05

it's found in instance

play12:07

instantiation for the variable x

play12:10

in our query and so at this point prolog

play12:14

will then respond with

play12:15

a yes or a true indicating that it has

play12:18

found a valid instantiation that makes

play12:22

the query true and then it will also

play12:25

indicate that that instantiation is

play12:27

for the variable x and the value then

play12:31

is 2205

play12:34

for that instantiation

play12:38

we'll now turn our attention to list

play12:40

structures

play12:41

in prolog so lists represent

play12:44

the second basic type of data structure

play12:47

that prolog supports

play12:49

the first basic data structure being

play12:52

atomic propositions

play12:53

that are used to represent relations

play12:56

we've previously discussed atomic

play12:58

propositions in quite a lot of detail

play13:02

so lists in prologue are very similar

play13:06

to the lists supported in the lisp and

play13:09

scheme functional programming languages

play13:12

that we discussed

play13:12

in the previous chapter lists

play13:16

consist of a number of elements

play13:19

and are implicitly terminated by

play13:22

an empty list the elements contained in

play13:26

a list can be a mixture of atoms

play13:29

atomic propositions and other terms

play13:32

including

play13:32

other lists so this means we can create

play13:36

arbitrarily nested list structures

play13:39

so over here we have an example of list

play13:42

notation

play13:43

in prolog and this is a simple list

play13:46

that contains three atoms notice

play13:50

that the list is delimited by means of

play13:52

square brackets

play13:54

and the list elements are separated by

play13:56

commas

play13:57

the three elements are apple

play14:00

prune and grape and note that all three

play14:04

of these start with a lowercase letter

play14:06

which indicates that they are atoms

play14:10

here we have an example of a more

play14:12

complex list

play14:13

this list contains two elements the

play14:16

first element

play14:17

is a nested list containing two atoms a

play14:20

and b and the second element

play14:24

is an atomic proposition describing the

play14:26

sun relation

play14:28

and the two parameters for this atomic

play14:31

proposition

play14:32

are the variable x and the atom bob

play14:36

empty lists are represented in a fairly

play14:39

intuitive fashion which we see

play14:41

over here they are simply the delimiting

play14:44

square brackets

play14:45

with nothing placed between them

play14:49

now we very often during list processing

play14:51

want to be able to access the

play14:54

head of a list in other words the first

play14:56

element of a list

play14:57

and then the tail of the list which

play15:00

would be the remaining elements

play15:02

in the list excluding the head

play15:05

now in scheme we saw that we used

play15:08

functions

play15:09

to access the head or the tail of a list

play15:13

in prologue we use this notation

play15:17

over here so again we delimit

play15:21

the list with square brackets but then

play15:24

we use

play15:24

a pipe symbol and to the left of the

play15:27

pipe symbol

play15:28

we have the head of the list which in

play15:30

this case is represented by

play15:32

a variable called x and to the right of

play15:36

the pipe

play15:36

we have the tail of the list which here

play15:39

is represented by the variable

play15:41

y now this kind of notation is used

play15:45

both to disassemble lists and to

play15:48

construct lists so when we disassemble

play15:51

lists

play15:52

we typically remove elements from the

play15:55

list one by one

play15:57

repeatedly removing the head from a list

play16:00

until

play16:00

eventually we have an empty list

play16:04

as the tail constructing lists

play16:07

conversely involves adding elements to a

play16:11

list one

play16:11

item at a time and to the head

play16:15

of the list so what we saw then

play16:18

in scheme was that we had list

play16:20

construction

play16:22

functions such as cons this is then

play16:25

not the case in prologue

play16:30

i'd like to take a moment now to discuss

play16:32

the general philosophy

play16:34

and approach that must be used when

play16:36

implementing prologue propositions

play16:38

that have to perform list processing

play16:42

so in general list processing in

play16:44

prologue must use a recursive approach

play16:47

in order to work through lists one

play16:49

element

play16:50

at a time this recursive strategy

play16:53

is similar to the recursive approach

play16:56

used when implementing list processing

play16:58

functions

play17:00

in a functional programming language

play17:02

such

play17:03

as scheme in our discussion on the

play17:06

previous chapter we looked at

play17:08

a few examples of these kinds of

play17:11

functions

play17:11

in the scheme programming language now

play17:14

it's important

play17:15

to understand that prologue propositions

play17:19

do not

play17:19

return results instead results are

play17:23

defined

play17:24

using parameters now the

play17:27

base cases and recursive cases are

play17:30

implemented as separate prologue

play17:33

statements

play17:34

the base cases are often atomic

play17:37

propositions

play17:38

that use variables and the recursive

play17:41

cases

play17:42

are rules that also use variables

play17:46

now it's important also to understand

play17:48

that the order

play17:49

of these statements is important

play17:53

and this is because prologue's matching

play17:55

process works

play17:56

from the top of a program to the bottom

play18:00

when matching against facts and rules

play18:03

during the resolution process

play18:06

so this then means that base case

play18:08

statements must appear

play18:10

first and recursive case statements must

play18:13

appear after the base case

play18:15

statements now recall from

play18:18

the first lecture on this chapter

play18:22

that prologue and logic programming

play18:24

languages

play18:25

in general aim to be context independent

play18:28

so this means that each statement should

play18:32

not depend

play18:33

on previous statements that appear

play18:35

before it within

play18:37

a program now because the order of

play18:40

statements is

play18:41

important when defining recursive list

play18:44

processing propositions in prolog

play18:47

this then unfortunately means that

play18:49

prologue isn't

play18:50

entirely context independent

play18:56

now sometimes in a prologue statement

play18:59

a value might not be relevant

play19:02

this happens fairly often in list

play19:05

processing propositions

play19:07

but we also see it in other contexts

play19:09

within prologue programs

play19:12

so an example of a situation where a

play19:15

value might not be relevant during list

play19:17

processing

play19:19

might be where we have to ignore the

play19:21

head of a list

play19:23

in this case we can then use an

play19:25

underscore character

play19:27

to replace the variable representing the

play19:31

head of the list

play19:32

this underscore character represents an

play19:35

anonymous variable

play19:37

which has no name associated with it

play19:40

the anonymous variable then indicates

play19:43

that we don't care what instantiation

play19:45

the variable gets

play19:47

during the unification process

play19:50

now in general the underscore character

play19:54

representing an anonymous variable

play19:56

would replace a variable that is unused

play20:00

to define

play20:01

a result in an atomic proposition

play20:04

or in a rule now

play20:08

the underscore character just serves

play20:11

to simplify our prologue implementations

play20:14

and it is not strictly speaking required

play20:18

so in a situation where a variable

play20:21

is unused within a result

play20:25

and we don't use an underscore character

play20:27

but instead

play20:28

use a variable name we may get

play20:32

a warning from our prologue interpreter

play20:35

indicating that the variable is unused

play20:38

but in general this won't cause any kind

play20:41

of

play20:42

problem when the prologue proposition

play20:45

is actually used

play20:49

we'll now look at three example

play20:51

implementations of prologue propositions

play20:54

that perform list manipulations our

play20:57

first proposition

play20:58

is the member proposition which defines

play21:01

a relation

play21:02

between two parameters the first

play21:05

parameter which is represented here by

play21:07

the variable x

play21:08

is a term and the second parameter

play21:11

represented by the variable y

play21:14

is a list now the member proposition

play21:17

should be true

play21:18

if the term x is contained within

play21:22

the list y so over here we have an

play21:26

example of how the member proposition

play21:28

can be used

play21:29

and this proposition should be true

play21:31

because the

play21:32

first parameter which is the atom a

play21:36

is contained within the second parameter

play21:40

which is a list containing the atoms

play21:43

b a and c

play21:46

so how will we then go about

play21:48

implementing this member proposition

play21:51

well we need to search through the list

play21:53

one element

play21:54

at a time i'm trying to find a match

play21:58

between

play21:58

the term and the element that we are

play22:01

currently

play22:02

looking at so this implies that we have

play22:06

to use

play22:06

a recursive strategy which means that we

play22:09

need a base case

play22:11

and a recursive case so we can state

play22:15

that a term is a member of the list if

play22:18

this term

play22:19

is either the head of the list or

play22:22

a member of the tail of the list the

play22:26

situation where the term

play22:27

is the head of the list corresponds to

play22:30

our base case

play22:32

because this terminates our recursion

play22:35

due to the fact that we have found the

play22:38

element in the list that we

play22:40

are searching for the situation where

play22:43

the term

play22:44

is a member of the tail of the list

play22:47

corresponds to our recursive case

play22:50

because

play22:51

the tail requires further processing

play22:54

after ignoring the head of the list

play22:58

so over here we have our implementation

play23:01

of the member proposition and we can see

play23:04

that we

play23:05

have two statements the first statement

play23:08

corresponds to our base case and the

play23:11

second statement corresponds to

play23:13

our recursive case our base case

play23:16

is represented by means of an atomic

play23:19

proposition

play23:20

and our recursive case is a bit more

play23:22

complex and is represented by means

play23:24

of a rule so let's look at

play23:28

our base case first here we specify

play23:31

that the variable element is a

play23:34

member of a list if

play23:38

this element is the head of the list

play23:42

notice that we have used an underscore

play23:45

symbol for the tail of the list

play23:47

this means that we are working with

play23:50

an anonymous variable which means we are

play23:53

not interested

play23:54

in the instantiation of this variable

play23:58

this makes sense because we don't care

play24:01

about

play24:02

the tail of the list because we have

play24:04

found

play24:05

the elements that we are searching for

play24:09

next we'll move on to the statement that

play24:12

defines

play24:13

our recursive case now here

play24:16

it's important to take notes of the fact

play24:19

that the order of the statements is

play24:21

important

play24:23

and this is because prologue matches

play24:25

from the top of the program

play24:27

to the bottom of the program so what

play24:30

this thing means

play24:31

is the second statement will only be

play24:33

matched

play24:34

in a situation where the first statement

play24:37

has not been matched in other words

play24:39

we have not found the base case

play24:43

for our search in this case we then

play24:46

know that the element is not the head of

play24:48

the list so we can discard

play24:50

the head of the list and then here we

play24:53

specify

play24:54

that the element represented by the

play24:57

variable element

play24:58

is a member of a list where the tail of

play25:02

the list is represented by the variable

play25:05

lis and the element

play25:09

is a member of lis

play25:12

lis again being the tail of the list

play25:16

so again here notice that we have used

play25:19

an underscore symbol in other words an

play25:21

anonymous variable

play25:23

for the head of our list and this is

play25:26

because

play25:26

we are not interested in an

play25:28

instantiation

play25:29

for that variable because we are

play25:32

discarding

play25:33

the first element in the list

play25:36

so notice also here that we do not

play25:40

need to create any prologue statements

play25:44

that relate to a situation where an

play25:47

element

play25:48

has not been found in other words where

play25:51

we have reached the

play25:52

end of the list if we reach the end of

play25:55

the list without the base case

play25:57

being satisfied then the entire

play26:01

member proposition will fail and we will

play26:04

then get

play26:04

a no or a false response this of course

play26:08

makes sense because we haven't found the

play26:11

elements that we are

play26:12

searching for now what i would like you

play26:16

to

play26:16

do at this point is pause the video and

play26:19

consider what would happen

play26:21

if we swapped the two statements so in

play26:23

other words

play26:24

we had the base case appearing after

play26:28

the recursive case

play26:31

so finally down here we have two

play26:34

example queries that are valid for the

play26:37

member proposition

play26:38

over here we are asking whether the atom

play26:42

a

play26:43

is a member of the list containing the

play26:47

atoms

play26:48

d b and c and of course here

play26:51

the atom a is not contained within this

play26:54

list which means that our member

play26:57

proposition

play26:58

will then fail and prologue will respond

play27:01

with no or false

play27:04

the second query over here

play27:07

asks prologue to find an instantiation

play27:11

for the variable

play27:12

x such that x is a member

play27:16

of the list containing the atoms a b and

play27:19

c

play27:20

so what will happen here is prolog will

play27:22

find an initial

play27:24

instantiation for the variable x which

play27:27

will be

play27:28

the atom a we can then re-query

play27:32

prologue again and in this case we are

play27:35

then asking prolog to find

play27:36

a second instantiation that makes this

play27:39

proposition

play27:40

true so this point prolog will then

play27:43

instantiate

play27:44

x to the atom b and will respond with

play27:48

a yes or a true result if we

play27:51

re-query another time then prologue will

play27:54

instantiate the x variable

play27:56

to the atom c and then if we try

play28:00

re-quering again

play28:01

after this prologue will not be able to

play28:03

find another instantiation of the

play28:05

variable x

play28:07

that is contained within the list

play28:12

our next prolog implementation is for an

play28:15

append proposition the append

play28:17

proposition

play28:18

defines a relation between three

play28:20

parameters

play28:22

here represented by the variables x y

play28:24

and z

play28:25

respectively all three parameters are

play28:28

lists so the append proposition

play28:31

is true if appending the list

play28:34

y to the end of the list x

play28:38

produces the list z as a result

play28:42

over here we have an example of how the

play28:44

append proposition

play28:45

could be used and this proposition

play28:48

should be true because if we append the

play28:51

list containing the atoms

play28:52

c and d to the end of the list

play28:55

containing the atoms a

play28:57

and b then the result should be

play29:00

a list containing the atoms a b c

play29:03

and d in that order

play29:07

so how will we then go about

play29:09

implementing the append

play29:10

proposition well we need to work through

play29:13

a list one element

play29:15

at a time so this means we have to use

play29:18

a recursive strategy with a base case

play29:21

and a recursive case so the approach

play29:24

that we will use is that we

play29:26

will append the second list to the tail

play29:29

of the first list to produce a result

play29:32

and then we prepend the head of the

play29:35

first list

play29:36

to the result so let's look at the

play29:39

strategy

play29:40

in relation to our example proposition

play29:44

over here what we are essentially doing

play29:47

then

play29:47

is we are working through the first list

play29:50

one element at a time and we are

play29:53

eliminating at each step

play29:55

the head of the list so with the first

play29:59

recursive step we eliminate the first

play30:01

element

play30:02

in the first list which is the atom a

play30:05

and that leaves us with a list

play30:06

containing only

play30:08

the atom b we then need

play30:11

to append our list containing the atom c

play30:14

and d to this list containing only the

play30:17

atom b

play30:18

however we haven't eliminated all of the

play30:21

elements within the list yet

play30:23

so we need to then eliminate the atom

play30:27

b which leaves us only then with

play30:30

the implicit tail of the list which as

play30:32

we've previously seen

play30:34

is an empty list at this point

play30:37

we have reached our base case because we

play30:40

are now appending the list containing

play30:42

the atoms c

play30:43

and d to an empty list and the result

play30:46

of that of course should simply be the

play30:49

list containing the atoms

play30:51

c and d so now that we've reached our

play30:55

base case

play30:56

we then return and unwind the call stack

play31:00

and as we unwind the call stack we then

play31:03

prepend each atom that we've eliminated

play31:06

from the first list and this happens

play31:09

in the reverse order of which they were

play31:13

removed so we then pre-pinned the atom

play31:16

b to the list containing the atoms c and

play31:19

d

play31:20

and this gives us the list containing

play31:23

the atoms

play31:23

b c and d then

play31:26

when we unwind to our final step we

play31:29

pre-pinned

play31:30

the atom a to the list containing the

play31:33

atoms

play31:34

b c and d and this gives us our final

play31:38

result which is the list containing the

play31:40

atoms

play31:40

a b c and d so over here

play31:44

we have an implementation of the

play31:47

prologue append proposition

play31:49

and again it notes that we have two

play31:51

statements the first statement

play31:53

representing the base case

play31:54

and the second statement representing

play31:57

the

play31:58

recursive case so our base case

play32:01

is fairly simple here we are appending a

play32:04

list

play32:04

represented by the variable list

play32:08

to an empty list and the result of this

play32:11

is simply list once again

play32:16

now we can move on to our recursive case

play32:19

which is a little more complicated

play32:21

and is implemented by means of a rule

play32:24

so here we are appending a list which is

play32:28

represented by the variable

play32:29

list 2 to a list where the head of this

play32:33

list is represented by the variable head

play32:36

and the tail of this list is represented

play32:38

by the variable

play32:40

list 1. now what we need to do

play32:44

is discard the head element from this

play32:46

list

play32:47

and append list two to the tail

play32:51

list one so this is done in the

play32:53

antecedent

play32:54

of our rule over here where we are

play32:57

appending

play32:58

list 2 to list 1 which is the

play33:01

tail of the first list then

play33:04

the result that we get is defined by the

play33:08

variable

play33:08

list 3. so finally we can now

play33:12

define our final result

play33:15

over here in the consequent

play33:18

and the final result then is

play33:21

the list 3 variable which is the list

play33:24

that we've

play33:26

created by means of this append

play33:29

operation

play33:30

over here with the head

play33:33

prepended to that list where the head

play33:36

is the first element of the first

play33:39

list so here we have

play33:43

four example queries that we could

play33:46

use which involve the append proposition

play33:50

the first query is relatively

play33:52

straightforward here we

play33:53

are asking prologue whether appending

play33:56

the list

play33:57

containing the atoms c and d to the list

play34:01

containing the atoms a

play34:02

and b produces a list containing the

play34:05

atoms

play34:06

a b c and d this of course is the case

play34:10

so therefore prolog will respond with

play34:12

yes or true

play34:14

however with the remaining three queries

play34:18

we now see the power of prologue

play34:21

propositions so what prologue allows us

play34:25

to do

play34:25

is to ask for an instantiation

play34:29

of any one of the three parameters

play34:33

as long as we provide sufficient

play34:36

information

play34:36

for the instantiation to take place

play34:39

which means that we provide

play34:40

values for the other two parameters

play34:44

so in our second query over here we are

play34:47

asking prologue

play34:48

what the result is of appending

play34:51

the list containing the atoms c and d

play34:55

to the list containing the atoms a and b

play34:58

prologue will then respond with yes or

play35:01

true and it will indicate that the

play35:02

instantiation for the variable

play35:04

x is the list containing the atoms a

play35:07

b c and d in the next query over here

play35:12

we are asking prologue what do we need

play35:15

to

play35:15

append to the list containing the atoms

play35:18

a

play35:18

and b in order to get a result which

play35:22

is the list containing the atoms a b c

play35:25

and d prologue can find an instantiation

play35:29

for this variable x because it has

play35:31

sufficient remaining information

play35:33

to perform the instantiation and it will

play35:37

then respond with

play35:38

yes or true and it will indicate that

play35:40

the instantiation for the variable

play35:42

x should be the list containing the

play35:46

atoms

play35:46

c and d finally in

play35:50

our last query we are asking prologue

play35:54

if we append the list containing the

play35:57

atoms c

play35:58

and d to a list and the result

play36:01

is the list containing the atoms a b c

play36:04

and d what must this list be that we

play36:07

append

play36:08

to once again prolog can answer this

play36:11

question because it has sufficient

play36:12

information

play36:13

so it will respond with a yes or true

play36:17

and indicate that the instantiation for

play36:20

the variable

play36:20

x must be the list containing the atoms

play36:24

a and b

play36:28

the final implementation example we'll

play36:30

look at is for

play36:31

a reverse proposition so the reverse

play36:34

proposition defines a relation between

play36:37

two parameters

play36:38

which are represented by the variables x

play36:41

and y respectively

play36:42

both x and y are lists so the reverse

play36:46

proposition

play36:47

is true if the list y is the reversed

play36:50

version

play36:51

of the list x over here we have

play36:55

an example of how the reverse

play36:57

proposition could be

play36:58

used and this proposition should be true

play37:01

because if we reverse the list

play37:03

containing the atoms

play37:05

a b and c in that order then we get

play37:08

a result which is the list containing

play37:11

the atoms

play37:12

c b and a in that order

play37:15

so what approach then will we use for

play37:17

implementing our reverse proposition

play37:20

well we need to work through the first

play37:22

list one element at a time

play37:24

so this again suggests that we have to

play37:27

use a recursive strategy

play37:29

with a base case and a recursive case

play37:33

so the approach that we will use is that

play37:35

we will first

play37:36

reverse the tail of the first list

play37:39

and then we will append the head of the

play37:41

first list

play37:42

to this reversed version of the tail

play37:46

now the subpending operation will be

play37:49

implemented

play37:50

by means of the append proposition

play37:53

that we defined in the previous slide

play37:58

so if we look at this procedure in terms

play38:01

of the application of our reverse

play38:04

proposition

play38:06

then what we are doing in this case is

play38:08

taking our first list which contains the

play38:11

atoms a b and c

play38:12

and we are reversing the tail of the

play38:15

list which is a list containing the

play38:17

atoms b

play38:18

and c so the reversed version of that

play38:21

tail should then

play38:22

be the list containing the atom c

play38:26

followed by the atom b and

play38:29

then we append the atom a which is the

play38:32

head of this list

play38:34

to the reversed version of that tail

play38:36

which then gives

play38:37

us our final result which is the list

play38:40

containing the atoms

play38:42

c b and a finally

play38:46

so what we are essentially doing here in

play38:48

a similar fashion

play38:49

to the append proposition that we looked

play38:53

at

play38:53

on the previous slide is we are

play38:56

eliminating elements

play38:58

from the first list one by one

play39:02

we are performing the append operations

play39:05

as we return our recursive calls in

play39:07

other words as the call stack

play39:10

unwinds so once again we will use an

play39:13

empty list

play39:14

to represent our base case

play39:18

and this is once again because we are

play39:21

eliminating elements from the first list

play39:23

until eventually we are left only with

play39:26

the implicit final tale

play39:28

of the list which is an empty list

play39:32

so over here we have our implementation

play39:34

of the reverse

play39:35

proposition and first of all we have our

play39:38

base case

play39:40

so the base case is very simple it

play39:42

simply states

play39:44

that if we reverse an empty list then

play39:46

the result

play39:47

is an empty list once again

play39:51

now if we look at our recursive case

play39:54

over here we see once again that we have

play39:56

to use

play39:57

a rule which is slightly more complex

play40:01

so we are reversing our first list

play40:04

over here and the first list consists

play40:07

of a head which is represented by the

play40:10

variable head

play40:11

and a tail represented by the variable

play40:14

tail so what we first need to do then

play40:17

is reverse this tail and this is done

play40:21

in our antecedent over here

play40:24

where we specify that we

play40:27

reverse the tail using a recursive

play40:31

application of the reverse proposition

play40:34

in order to get

play40:35

a result which we will indicate by means

play40:38

of

play40:39

a variable called result we then perform

play40:43

an append operation using the append

play40:46

proposition that we previously defined

play40:48

and here we are appending then the head

play40:51

which is the first element

play40:53

of the first list to the

play40:56

result which is the result

play40:59

of reversing the tail

play41:02

and the result then of the subpending

play41:05

operation

play41:06

is a list which we will refer to

play41:10

as the variable list

play41:13

this list then is the final result

play41:16

which is then the second parameter of

play41:19

the reverse

play41:20

proposition now notice that

play41:23

the head that we use in this append

play41:26

operation

play41:27

is a list as is indicated by means of

play41:30

the opening

play41:31

and closing square brackets so why do we

play41:34

have to provide

play41:35

those opening and closing square

play41:37

brackets

play41:39

well the reason is that as we previously

play41:42

saw our definition of the append

play41:44

proposition

play41:45

works with three lists so this means

play41:48

that

play41:49

our second parameter must be a list

play41:52

however the head of a list is

play41:56

simply an element in the example that we

play42:00

used it would simply be

play42:01

an atom so we therefore cannot use

play42:05

an atom as this second parameter over

play42:08

here we must use a list

play42:10

and so we simply convert this head

play42:12

element to a list

play42:13

by surrounding it by these square

play42:16

brackets

play42:18

so finally we have three examples of

play42:21

valid

play42:22

queries that use the reverse proposition

play42:25

the first one again is fairly simple so

play42:28

here we

play42:29

are asking prologue whether the list

play42:32

containing the items

play42:33

cb and a is a reversed version of the

play42:37

list containing the atoms

play42:39

a b and c of course this is the case

play42:42

so prologue will respond with yes or

play42:45

true

play42:46

we can once again use variables in

play42:50

our queries which we do in the last two

play42:52

example queries over here

play42:55

so in this case we are asking prologue

play42:58

what is the reversed version of

play43:01

the list containing the atoms a b and c

play43:05

prologue can find an instantiation for

play43:08

the variable x

play43:09

over here so it will respond with yes

play43:12

or true and it will then indicate that

play43:15

the instantiation

play43:16

for x is the list containing the atoms

play43:19

c b and a in that order

play43:22

in our final query over here we are

play43:25

asking prologue

play43:28

what list do we have to reverse

play43:31

in order to get the list that contains

play43:33

the atoms a b

play43:35

and c in that order again prologue can

play43:38

answer this query so it will respond

play43:40

with a yes

play43:41

or true and then it will indicate that

play43:43

the instantiation

play43:45

for the variable x must be the

play43:48

list containing the atoms c b and

play43:51

a in that order

play43:54

so hopefully these queries that involve

play43:57

variables illustrate the flexibility

play44:00

of the prologue programming language

play44:03

it's important

play44:04

to note that we don't need to define

play44:07

new reverse propositions in order to

play44:10

use the reverse proposition in this way

play44:14

so in other words we simply define our

play44:16

reverse proposition

play44:18

which produces a result by means of the

play44:21

second parameter

play44:22

and then the queries will

play44:26

work regardless of which parameter we

play44:29

specify

play44:30

by means of a variable that needs to be

play44:32

instantiated

play44:34

this is particularly interesting in the

play44:36

previous example that we looked at for

play44:38

our implementation

play44:39

of the append proposition and this

play44:42

is because using the append proposition

play44:47

with variables in the three contexts

play44:50

of the three separate parameters would

play44:54

typically

play44:54

require three separate functions to be

play44:57

implemented

play44:58

in an imperative programming language

play45:00

like c

play45:01

plus or java

play45:05

we will now take a look at four

play45:07

deficiencies that are associated with

play45:10

the prologue

play45:10

programming language these deficiencies

play45:14

are the reason that prologue is not more

play45:17

widely used

play45:18

in a practical context so

play45:21

the first deficiency is resolution order

play45:24

control

play45:26

the second deficiency is referred to as

play45:28

the

play45:29

closed world assumption the third

play45:31

deficiency

play45:32

is called the negation problem and then

play45:35

finally

play45:36

we have some intrinsic limitations

play45:39

associated

play45:40

with certain kinds of computations

play45:43

that prologue cannot perform efficiently

play45:46

we'll look at each of these deficiencies

play45:49

in order

play45:50

over the remaining slides

play45:54

the first deficiency associated with the

play45:57

prologue programming language

play45:59

relates to resolution order control

play46:03

now in order to understand the problems

play46:05

that go hand in hand

play46:06

with resolution order control we must

play46:09

first remember that prologue always

play46:11

matches

play46:12

from top to bottom when it is

play46:14

considering facts and rules

play46:16

and from left to right when it is

play46:18

working through

play46:19

sub goals now one of the consequences

play46:23

of this is that a programmer can

play46:26

directly

play46:26

affect the efficiency of a prologue

play46:30

program and one simple way that they can

play46:33

do this

play46:34

is by placing rules that are more likely

play46:36

to succeed

play46:37

higher up in their program

play46:41

this means that these rules will

play46:44

tend to be matched earlier which means

play46:47

that there will be fewer matches that

play46:50

will

play46:51

fail and this then results in fewer

play46:54

computational

play46:55

steps when the prologue program is

play46:58

executed

play47:00

now this in itself is not a serious

play47:03

problem it's essentially

play47:05

just an optimization that can be

play47:07

performed by a programmer

play47:09

however what this does do is reduce

play47:12

the context independence of prologue

play47:16

and as we've previously seen context

play47:18

independence

play47:19

is a major goal of all logic

play47:22

programming languages a more serious

play47:25

problem

play47:26

however is that resolution order

play47:29

can lead to non-terminating recursions

play47:32

in certain cases so in order to

play47:36

illustrate this

play47:37

we'll look at an example

play47:40

within this example we have two

play47:43

alternate

play47:44

implementations of the ancestor

play47:46

proposition

play47:47

which defines a relation between

play47:50

two parameters now we will assume

play47:54

that both of these parameters are atoms

play47:58

in addition we have a parent proposition

play48:02

which specifies that one atom is the

play48:05

parent of another atom

play48:09

now we will consider in both of these

play48:12

cases

play48:13

that an atom is considered to be an

play48:16

ancestor

play48:16

of itself this is of course not accurate

play48:20

in a real world context however it works

play48:24

for this example

play48:27

so we then also consider one atom to be

play48:30

the ancestor of another atom

play48:33

if there is a series of

play48:36

parents that link the first

play48:39

atom to the second atom in the ancestor

play48:44

proposition so we specified in this case

play48:48

by means of a rule and here we specify

play48:52

that x is the ancestor of

play48:56

y if a z exists

play48:59

such that z is an ancestor

play49:03

of y and then x

play49:06

is the parent of this

play49:09

z ancestor so this of course

play49:13

then makes sense in an intuitive

play49:16

fashion but how will this proposition

play49:20

actually function if we issue a query to

play49:24

prologue

play49:24

using the ancestor relation

play49:29

well this will work in a situation

play49:32

where we have an atom that is an

play49:34

ancestor of itself

play49:36

obviously because this is the base case

play49:39

and it will also work

play49:40

in a situation where x

play49:43

and y are directly related by means

play49:47

of a parent proposition however in a

play49:50

situation where x and y

play49:52

are not directly linked by a parent

play49:56

proposition we will then

play49:59

have to move on to the antecedent

play50:03

of our rule and prologue then

play50:06

works from the left hand side to the

play50:08

right hand side

play50:09

treating the ancestor proposition as a

play50:13

goal

play50:13

and then the parent proposition as a

play50:16

second goal

play50:17

so before we can move on to the parent

play50:20

proposition we must first of all

play50:22

satisfy the ancestor proposition

play50:26

what will happen here then is that

play50:29

prologue will attempt to find an

play50:31

instantiation

play50:32

for zed such that zed is an

play50:35

ancestor of y the second atom in the

play50:40

ancestor proposition this

play50:43

will ultimately result in prologue then

play50:46

matching against the rule once again

play50:50

and this will then continue happening

play50:53

over and over

play50:54

until eventually prologue runs out of

play50:57

memory we will never get to a situation

play51:00

where we can then attempt to satisfy the

play51:03

second sub-goal

play51:05

which is the parent proposition

play51:08

now let's look at the second

play51:10

implementation over here

play51:12

and we see that the base case is exactly

play51:15

the same

play51:16

as in the previous implementation

play51:19

however our rule is slightly different

play51:22

and the only difference

play51:23

is that the two propositions

play51:26

in the antecedent of the rule are

play51:29

swapped

play51:30

when we compare them to the first

play51:33

rule that we looked at so in this case

play51:37

the ancestor proposition will work

play51:40

correctly

play51:41

because we first of all attempt to

play51:44

find a parent x of another atom

play51:48

z we can of course then satisfy

play51:52

this proposition as a sub goal

play51:55

because we have parent relations that

play51:58

are specified by means of

play52:00

rules in our prologue program so

play52:04

we then create an instantiation for z

play52:07

and then we test to see whether zed is

play52:10

an

play52:10

ancestor of why this will then

play52:13

eventually allow us to perform all of

play52:17

the

play52:17

matches that are required which will

play52:20

then

play52:20

either prove or ultimately disprove

play52:23

that x is an ancestor of y

play52:30

prologue provides an additional feature

play52:33

referred to

play52:33

as a cut and cuts are not

play52:37

deficiencies related to the prologue

play52:40

programming language

play52:41

but they are very closely related to

play52:43

resolution order control cuts

play52:46

allow a programmer to explicitly control

play52:49

backtracking which is performed during

play52:51

prologues resolution process

play52:54

so a cut is a special kind of goal

play52:57

and is represented by means of an

play53:00

exclamation mark symbol

play53:02

this goal is always satisfied

play53:05

however the cut and any sub-goals that

play53:08

appear to the left of the cut

play53:10

cannot be re-satisfied by means of

play53:13

backtracking

play53:14

now cuts can be very complex and there

play53:18

are

play53:18

different kinds of cuts but we are not

play53:21

interested in

play53:22

this level of detail instead we will

play53:25

simply illustrate how cuts

play53:27

work by means of a simple example

play53:31

so this example presents two

play53:34

implementations

play53:35

of a proposition called valid member

play53:39

the valid member proposition has a

play53:42

single parameter

play53:43

which we will assume is an atom and it

play53:46

is represented here by means

play53:48

of the variable x so the valid member

play53:52

proposition

play53:52

is meant to check first of all whether x

play53:55

is

play53:56

a member of an organization and secondly

play53:59

whether x satisfies some kind of

play54:02

requirement

play54:03

to be a valid member so in order to

play54:06

determine whether x is a valid member we

play54:09

need to look at

play54:10

the antecedent of this rule and we see

play54:12

that the antecedent

play54:14

has two sub-goals the first

play54:17

sub-goal tests to see whether x

play54:20

is a member of a list by means of

play54:24

the member proposition now we assume

play54:28

that this list contains atoms and that

play54:31

these

play54:32

atoms represent individual members

play54:35

of an organization the

play54:38

ellipses between the square brackets of

play54:41

the list

play54:42

simply indicate that the list

play54:45

contains a lot of atoms and is therefore

play54:48

very long we also assume

play54:51

that the list contains no duplicate

play54:54

elements

play54:56

so once our first sub-goal has

play54:58

determined that x

play55:00

is a member of this list we can then

play55:03

move on to the second sub

play55:05

goal and this sub goal uses a test

play55:08

proposition

play55:09

in order to determine whether x

play55:11

satisfies

play55:12

the requirements for being a valid

play55:15

member

play55:16

so this is then a sensible

play55:18

implementation

play55:20

for the valid member proposition however

play55:23

let's look at how prolog will actually

play55:27

interpret the valid member proposition

play55:30

if it is used in a query

play55:34

so let's assume then that we test

play55:36

whether a particular atom

play55:38

is a valid member and we also assume

play55:42

that this atom is contained within

play55:45

the list so in other words our first sub

play55:48

goal

play55:49

succeeds we then move on to

play55:52

our second sub goal however we assume

play55:55

then that x fails its test so in other

play55:58

words

play55:59

the second sub goal is not

play56:02

satisfied now we know

play56:05

by means of our understanding of the

play56:08

resolution process

play56:10

that prologue now needs to backtrack to

play56:12

the

play56:13

previous sub-goal and this will then

play56:16

continue the search for x

play56:19

within the list however

play56:22

we know that the list contains no

play56:25

duplicate elements

play56:26

so this continued searching is then

play56:29

guaranteed to

play56:31

fail once the remainder of the search

play56:35

then fails

play56:36

then our entire application of the valid

play56:39

member proposition

play56:41

fails however this continued

play56:45

search is unnecessary and therefore

play56:48

introduces additional computational

play56:50

complexity

play56:51

which is not necessary so now let's look

play56:56

at

play56:56

our second implementation of the valid

play56:59

member proposition

play57:01

we can see that this valid member

play57:03

proposition is implemented in exactly

play57:05

the same way

play57:07

as our first example and it has

play57:10

the same two sub-goals however between

play57:14

the two sub-goals

play57:16

we have an additional sub-goal which is

play57:19

a cut represented by the exclamation

play57:22

mark symbol so let's assume exactly

play57:26

the same scenario that i described for

play57:29

the previous implementation of the valid

play57:32

member proposition

play57:34

so again we then find x within

play57:37

our list we then move on to the next sub

play57:40

goal which is our cut

play57:42

and the sub goal is automatically

play57:45

satisfied

play57:46

we then move on to our last sub goal

play57:49

where we perform

play57:50

our test on x and we again assume that

play57:53

this test

play57:54

fails so this point prologue would then

play57:57

backtrack

play57:58

however it encounters the

play58:02

exclamation mark symbol which represents

play58:05

a

play58:05

cut and this means it cannot backtrack

play58:08

past the cut

play58:09

to the first sub-goal this then

play58:13

means that our application of the valid

play58:16

member proposition will immediately fail

play58:19

without backtracking to perform

play58:22

a continued search for x within

play58:25

the list we've therefore eliminated

play58:28

the additional search steps that are not

play58:32

required

play58:33

and this means that this implementation

play58:35

of the valid member proposition

play58:37

is more efficient now what i would like

play58:40

you to do at this point

play58:42

is to pause the video and see if you can

play58:45

think

play58:45

of a another solution to

play58:48

efficiently implement the valid member

play58:51

proposition

play58:52

but without using a cut

play58:57

the second deficiency that is associated

play59:00

with prologue is referred to

play59:02

as the closed world assumption now

play59:05

recall

play59:06

that prologue can only prove things

play59:08

using facts

play59:09

and rules that have been provided to it

play59:13

so if we assume that we issue a query

play59:16

to prolog and prologue answers with

play59:19

a yes or true response then it means

play59:23

that the query can be proven true

play59:27

however if prolog answers no or

play59:30

false to the query then it means that

play59:32

the query cannot be

play59:34

proven and this doesn't necessarily mean

play59:37

that the query is false

play59:40

we may get for example a no or a false

play59:44

response

play59:45

if we have insufficient facts to prove

play59:48

a query or the rules required to prove

play59:51

the query

play59:52

are implemented incorrectly now there's

play59:55

no feedback mechanism

play59:56

indicating that a no or a false response

play60:00

is due to an implementation mistake or

play60:03

due to a query

play60:05

actually being false and this can

play60:08

potentially lead to

play60:09

a programmer drawing the wrong

play60:12

conclusions from

play60:14

a negative response

play60:18

the next prologue deficiency that we'll

play60:21

look at

play60:21

is referred to as the negation problem

play60:24

and this

play60:25

is fairly closely related to the closed

play60:28

world assumption we just discussed

play60:30

now the negation problem relates to the

play60:32

fact that it is difficult

play60:34

to handle logical negations within

play60:37

prolog

play60:38

so in order to illustrate this let's

play60:41

look at

play60:42

a simple implementation and here we've

play60:45

provided

play60:46

two facts as well as a single

play60:49

rule to prologue the first fact states

play60:52

that

play60:53

bill is jake's parent and the

play60:56

second fact specifies that bill is also

play61:00

the parent of

play61:01

shelly next we have our rule that

play61:04

specifies

play61:05

a sibling proposition and it specifies

play61:09

that two atoms x and y are siblings

play61:13

if there exists an m such that

play61:17

m is the parent of x and m

play61:20

is also the parent of y

play61:23

so this implementation then seems to

play61:26

make sense

play61:27

however let's consider a situation where

play61:30

we provide

play61:31

this query to prolog so here we are

play61:34

asking prologue to find

play61:36

instantiations for x and y

play61:39

such that x and y are siblings

play61:43

now we would assume then that prologue

play61:46

would

play61:47

instantiate x and y to jake

play61:50

and shelby however what we find

play61:53

is that prologue responds with a yes or

play61:56

a true

play61:57

indicating that it can find a valid

play62:00

instantiation

play62:01

but then it instantiates x and y

play62:05

both to jake now why does this happen

play62:09

well put simply there is nothing

play62:12

explicitly

play62:13

telling prologue that x and y must be

play62:16

different atoms but to explain this on a

play62:19

more

play62:20

technical level we can look look at how

play62:22

the resolution process

play62:24

um deals with this query

play62:27

so the resolution process will then

play62:30

consider

play62:30

the two sub goals in the antecedent of

play62:33

our rule

play62:34

and it will first of all try to find

play62:37

a parent m of x

play62:41

so we know then that the matching

play62:43

procedure performed by prologue begins

play62:45

at the top of the program and moves to

play62:47

the bottom

play62:48

so this first sub goal will then

play62:52

match to the first fact so in other

play62:55

words

play62:56

m will be instantiated to bull

play62:59

and x will be instantiated to jake

play63:03

next we need to move on to the second

play63:05

sub goal

play63:06

but this sub goal is satisfied

play63:09

independently of the first

play63:11

sub goal so once again prologue will

play63:14

then begin its search

play63:15

from the top of the program and move

play63:17

towards the bottom

play63:18

and again it can then satisfy this

play63:21

second sub goal with the first fact that

play63:25

has been provided

play63:26

which once again then states that bill

play63:28

is the parent of jake

play63:30

therefore m is once again

play63:34

bull and y has been instantiated

play63:38

to jake so this is why

play63:41

both x and y are instantiated

play63:44

to the atom jake so

play63:47

how can we then solve this problem

play63:50

well we can approach this in a fairly

play63:53

simple fashion

play63:54

by means of rewriting the

play63:58

sibling proposition and we do this

play64:01

by adding a third sub goal

play64:04

to the antecedent of our rule

play64:07

and this sub goal then uses the

play64:10

not operator that prolog provides

play64:14

and the not operator is then satisfied

play64:18

if its parameter is not satisfied

play64:22

so in other words this goal will only be

play64:24

satisfied if

play64:26

the statement that x is equivalent to y

play64:29

fails this will then ensure

play64:32

that x is not instantiated to jake while

play64:36

y

play64:36

is also instantiated to jake and

play64:39

therefore

play64:40

we will get the correct response that we

play64:42

expect

play64:45

now it is very important to understand

play64:48

that the not

play64:49

operator doesn't function like a true

play64:52

logical not as i previously mentioned

play64:55

the

play64:55

not operator succeeds if its parameter

play64:58

proposition

play64:59

fails however we saw when we were

play65:03

discussing the closed world assumption

play65:05

that a proposition fails if prologue

play65:09

can't prove

play65:10

its truth and this doesn't then

play65:13

necessarily mean that the parameter is

play65:16

actually false so if we look at the use

play65:20

of the not

play65:20

operator as it appeared in the example

play65:23

that we looked at

play65:24

on the previous slide this use

play65:27

of the not operator means that the

play65:30

resolution process

play65:31

cannot prove that x is the same as

play65:34

y so in other words there are no

play65:38

facts that state that x and y are equal

play65:41

to one another

play65:43

it however doesn't mean that x is not

play65:46

equal to y so in order to actually

play65:50

properly establish that two atoms

play65:52

are unequal we would need to

play65:55

implement a separate fact for each pair

play65:58

of atoms

play66:00

which would specify that these two atoms

play66:02

are

play66:03

not equivalent to each other now of

play66:06

course this approach

play66:07

is impractical for any moderately large

play66:10

set

play66:11

of atoms and therefore we typically

play66:14

don't use this approach in practice and

play66:17

we therefore

play66:18

need to rely on the not operator even

play66:21

though

play66:21

it isn't actually a true logical knot

play66:27

finally probably the biggest deficiency

play66:30

associated with prologue

play66:32

is that there are intrinsic limitations

play66:35

associated with the resolution process

play66:38

that prologue performs

play66:40

this means that there are certain kinds

play66:42

of tasks that are simply impossible

play66:45

to specify efficiently so

play66:48

over here we have an implementation

play66:51

example

play66:52

of one such case and we've actually

play66:55

discussed this

play66:56

example previously in the first lecture

play66:59

on this chapter

play67:00

when we were discussing first order

play67:03

predicate calculus

play67:05

so here we are defining a sort

play67:08

proposition and the sort proposition

play67:11

states

play67:12

that new list is a sorted version of old

play67:16

list

play67:17

if new list is a permutation

play67:20

of old list in other words a reordering

play67:23

of the elements in old list

play67:25

and new list is also sorted

play67:29

we test where the new list is sorted by

play67:32

means of

play67:32

the sorted proposition which is defined

play67:36

over here and the sorted proposition

play67:39

essentially just

play67:40

defines the characteristics of a sorted

play67:43

list

play67:45

so how does prolog then actually go

play67:47

about

play67:48

sorting old list well essentially it

play67:52

generates

play67:53

a permutation of old list and then it

play67:56

checks to see whether this permutation

play67:59

is sorted if this permutation isn't

play68:02

sorted then it generates

play68:04

another different permutation of old

play68:06

list

play68:07

and then tests to see with this new

play68:09

permutation is sorted

play68:11

it continues doing this until eventually

play68:15

it generates a permutation that is a

play68:18

sorted version of old list

play68:21

so this can obviously take a very long

play68:24

time and it may in fact require

play68:26

that prologue generate every possible

play68:29

permutation

play68:30

of old list so this is

play68:33

then a very inefficient mechanism for

play68:37

sorting a list

play68:38

however it is the only way that we can

play68:41

define

play68:42

a sorting of a list within

play68:45

the prologue programming language

play68:49

finally we will finish this lecture by

play68:52

looking at

play68:53

a few practical application areas for

play68:56

logic programming so first of all

play68:59

logic programming languages have been

play69:01

used in relational

play69:03

database management systems and here

play69:06

they

play69:06

are used to implement intelligent query

play69:09

systems

play69:10

for these databases which allow a user

play69:14

to perform a logical query

play69:17

on the contents of a relational database

play69:21

secondly logic programming languages

play69:23

have been used within

play69:24

expert systems and expert systems

play69:27

are essentially a set of rules

play69:30

that are used within a decision making

play69:34

system obviously logic programming

play69:37

languages make sense

play69:38

because they support rules and expert

play69:41

systems are based on rules

play69:44

and then finally logic programming

play69:46

languages such as

play69:48

prologue have been used for natural

play69:50

language processing

play69:52

in the domain of artificial intelligence

play69:56

all right so that then concludes our

play69:58

discussion on chapter 16.

play70:01

in the next lecture we will move back to

play70:04

earlier chapters

play70:06

where we will skip chapters three and

play70:08

four

play70:09

and begin looking at chapter five

play70:12

of the textbook

Rate This

5.0 / 5 (0 votes)

Related Tags
Logic ProgrammingProlog LanguageArithmetic OperationsList StructuresRecursive ApproachData StructuresResolution ProcessExpert SystemsNatural LanguageAI Applications