AI Project File (1) 5465
AI Project File (1) 5465
B.Tech (CS)
Practical File
1
TABLE OF CONTENTS
2
Chapter-1
Prolog
History and Background
Prolog was created in the early 1970s by Alain Colmerauer and Philippe Roussel at the University of Aix-
Marseille in France. Their goal was to develop a language that could efficiently process natural language and
serve as a practical tool for knowledge representation. Prolog's design was heavily influenced by the work of
logician and mathematician Alain Turing, who proposed the idea of Universal Turing Machines.
The foundation of Prolog lies in the field of formal logic, particularly in first-order logic. It borrows concepts
from the field of predicate calculus, which involves the use of logical quantifiers and predicates to express
relationships between objects or concepts. Prolog combines these logical foundations with automated logical
inference systems, enabling it to make deductions based on given facts and rules.
In Prolog, facts are stated as simple assertions about the world, while rules define logical inferences based on
these facts. For example, consider a simple knowledge base about animals:
animal(cat).
animal(dog).
mammal(X) :- animal(X).
Here, we state that "cat" and "dog" are animals using facts. We also define a rule stating that if something is
an animal, it is also a mammal. This rule is denoted by the :- symbol, which reads as "if" or "implies."
To interact with Prolog, we pose queries to the system based on the defined facts and rules. For example, we
can ask, "Is a cat a mammal?" Prolog will process this query and respond with "true" since we have
explicitly defined that "cat" is an animal and that all animals are mammals.
Prolog employs a technique known as backtracking to explore different possibilities and find solutions. It
will systematically explore the knowledge base, trying to match facts and rules until a solution is found or all
possibilities have been exhausted. This search process is known as a proof search or resolution.
One of the key advantages of Prolog is its ability to perform symbolic reasoning and symbolic computations.
It excels at handling complex, knowledge-intensive domains where it is important to reason logically about
relationships and constraints. Prolog's declarative nature allows us to focus on what needs to be achieved
rather than how to achieve it.
3
Another significant difference lies in the evaluation strategy. Prolog uses a form of depth-first search to
explore the search space of possible solutions. This approach can lead to more efficient solutions for
problems that have a large number of potential solutions or where a complete exploration of the space is not
necessary.
However, it is important to note that Prolog is not a universally applicable solution for all types of
programming tasks. It is particularly well-suited for tasks involving symbolic reasoning, inference, and
knowledge representation. For other types of problems, such as numerical computations or high-
performance tasks, other programming paradigms may be more suitable.
Prolog programs are composed of a series of statements, which are called clauses. Each clause consists of a
predicate, followed by one or more arguments enclosed in parentheses. The predicate represents the action
or relation being asserted, while the arguments provide the necessary information for that action or relation.
Prolog follows a predicate logic approach, where the truth of a statement is evaluated based on its logical
representation. The syntax of Prolog is primarily based on terms and variables.
In Prolog, variables are denoted by an uppercase letter or an underscore (_) at the beginning of their names.
They act as placeholders for unknown values and can be used to instantiate different objects during the
execution of a program.
Atoms in Prolog are used to represent constants and are denoted by lowercase letters or a series of characters
enclosed in single quotes (''). They can represent anything from numbers to words or even complex terms.
Prolog allows the composition of more complex data structures using structures. A structure is composed of
a functor (a predicate) and a number of arguments enclosed in parentheses. For example, the structure
point(3, 5) defines a point in two-dimensional space with coordinates (3, 5).
Predicates in Prolog represent relationships or actions and are the core building blocks of the language. They
are defined by a predicate name followed by a list of arguments. Predicates can also be defined with multiple
clauses, providing different patterns for different situations.
4
Clauses in Prolog are logical statements that express facts or rules. A fact is a clause that simply asserts a
relationship between objects. For example:
father(john, tom).
This fact states that John is the father of Tom. By querying the database, Prolog can infer this relationship
based on the provided facts and rules.
Rules, on the other hand, define logical implications or conditions. They are composed of a head and a body.
The head represents the goal to be achieved, while the body consists of a conjunction of subgoals that must
be satisfied for the rule to be true.
This rule says that X is the grandfather of Y if X is the father of Z, and Z is the father of Y.
Prolog's syntax and structure enable the creation of powerful knowledge bases and rule-based systems. With
its ability to perform logical inference, Prolog has found wide application in fields such as expert systems,
natural language processing, and automated reasoning.
Features of Prolog
1. Logic-Based Programming Paradigm: Prolog follows the logic programming paradigm, which is
based on formal logic. In this paradigm, programs are expressed as collections of logical statements,
or rules, rather than sequences of imperative commands. This allows programmers to focus on
defining relationships between data rather than specifying explicit instructions for how to compute
results.
2. Rule-Based Programming: In Prolog, programs are composed of facts and rules. Facts represent
basic assertions about the world, while rules define how to infer new facts from existing ones. For
example, a rule might state that "X is a parent of Y if X is a mother of Y or X is a father of Y."
3. Pattern Matching: Prolog employs pattern matching to find solutions to queries. When a query is
made, Prolog attempts to match the query against available facts and rules. If a match is found,
Prolog can instantiate variables in the query to satisfy the match.
4. Backtracking: Backtracking is a fundamental feature of Prolog. If Prolog cannot find a solution
using the current set of choices, it automatically backtracks and explores alternative paths. This
allows Prolog to exhaustively search for solutions to complex problems.
5. Unification: Unification is the process Prolog uses to match query patterns with available facts and
rules. It attempts to make query patterns identical to available facts and rules by instantiating
variables. For example, the query ancestor(X, Y) can be unified with the rule ancestor(X,
Y) :- parent(X, Y) by instantiating the variable Y.
6. Predicate Logic: Prolog programs are composed of predicates, which represent relationships
between objects. Predicates consist of a name and arguments. For example, parent(X, Y) is a
predicate that represents the relationship "X is a parent of Y." Predicates can be combined using
logical connectives such as conjunction (,), disjunction (;), and negation (not).
7. Recursion: Prolog supports recursion as a fundamental control structure. Recursive predicates allow
Prolog programs to solve problems involving repetitive or recursive structures. For example, a
recursive predicate can be used to compute factorial or traverse tree structures.
8. Inference Engine: Prolog can be used to build inference engines for expert systems and knowledge-
based applications. It excels at representing and reasoning with knowledge and logical inference.
Prolog's backward chaining mechanism enables it to infer conclusions from given premises.
5
9. Symbolic Computation: Prolog is well-suited for symbolic computation tasks such as symbolic
mathematics, reasoning, and integration. It can manipulate symbolic expressions and perform
symbolic computations using logical inference.
10. Natural Language Processing (NLP): Prolog's ability to represent and manipulate symbolic
structures makes it suitable for tasks in computational linguistics and NLP. It can be used for parsing,
semantic analysis, and other tasks involving natural language understanding.
11. Database Querying: Prolog can be used to query and manipulate databases. Its pattern matching and
logic-based approach make it suitable for querying structured data stored in databases. Prolog's
querying capabilities can be extended using database interface libraries.
12. Meta-Programming: Prolog allows programs to reason about other programs and manipulate their
structures. This capability enables powerful meta-programming techniques such as program
transformation, automatic program generation, and reflective programming.
6
Chapter-2
LISP
History and Evolution of LISP
LISP, which stands for "LISt Processing," is one of the oldest high-level programming languages still in use
today. It was developed in the late 1950s by John McCarthy, an influential computer scientist, as a practical
and efficient language for artificial intelligence (AI) research. LISP was specifically designed to manipulate
symbolic expressions and lists, which made it ideal for AI programming tasks, such as natural language
processing and problem-solving.
The early versions of LISP were implemented on mainframe computers like the IBM 704. McCarthy's
original LISP language introduced important concepts that are still used in modern programming languages
today, such as the use of parentheses for grouping and expressing computations. These parentheses, known
as S-expressions, are a fundamental part of LISP syntax.
Over the years, LISP evolved and went through several iterations. The most notable versions include LISP
1.5, MacLisp, InterLisp, Common Lisp, Scheme, and Emacs Lisp. Each of these variations introduced new
features, improved performance, and addressed different needs of the programming community.
LISP is known for its unique set of features and characteristics that distinguish it from other programming
languages. Here are some of the key features of LISP:
Expressive Power:
LISP offers a rich set of language constructs and features that allow programmers to express complex ideas
concisely. It provides a flexible syntax that allows code and data to be interchangeably manipulated. This
capability is often referred to as "code is data" or "homoiconicity."
Dynamic Typing:
LISP utilizes dynamic typing, which means that variable types are determined at runtime rather than being
explicitly declared. This flexibility allows for more interactive and exploratory programming.
Garbage Collection:
LISP employs automatic garbage collection to manage memory. This feature relieves programmers from
manually allocating and deallocating memory, making LISP a more convenient language to work with.
First-Class Functions:
In LISP, functions are treated as first-class citizens. This means that functions can be assigned to variables,
passed as arguments to other functions, and returned as results. This higher-order function capability makes
LISP well-suited for functional programming paradigms.
Symbol Manipulation:
LISP's extensive support for symbolic manipulation makes it a powerful tool for AI and symbolic
computation. It allows users to build and analyze complex data structures, such as trees and graphs, in a
7
straightforward manner.
LISP is often categorized as a functional programming language due to its support for functional
programming paradigms. In functional programming, computation is treated as the evaluation of
mathematical functions, and LISP heavily promotes this programming style.
One of the defining characteristics of functional programming is that functions are pure, meaning they have
no side effects and always return the same result for the same input. LISP provides the necessary tools to
write pure functions, including support for recursion, higher-order functions, and anonymous functions (also
known as lambda expressions).
Recursion is a powerful technique in LISP that allows functions to call themselves. This enables concise and
elegant solutions to problems that can be naturally represented through recursive structures, such as trees and
lists.
Higher-order functions, as mentioned earlier, enable the manipulation of functions as data. LISP
programmers can pass functions as arguments to other functions or return them as results, providing a level
of flexibility and composability not seen in other programming languages.
Lambda expressions are anonymous functions that can be defined on the fly and passed directly as
arguments to other functions. This feature allows for the creation of ad-hoc functions without the need to
define them separately.
LISP's combination of expressive power, dynamic typing, garbage collection, symbol manipulation, and
support for functional programming makes it a popular choice for AI researchers and programmers. Its
longevity and adaptability have ensured that LISP continues to be used and appreciated in numerous
domains within the field of artificial intelligence.
LISP is unique in that it treats code as data and data as code, allowing for dynamic and expressive
programming. Functions in LISP are defined using the defun special form, which stands for "define
function." Let's dive into the details of defining functions in LISP.
LISP functions are defined using the defun special form followed by the function name, a list of
parameters, and the body of the function. Here's an example that defines a simple function called square:
In this example, square takes a single parameter x and returns the square of x. The body of the function
8
consists of a single expression, which is multiplied by itself using the * operator.
LISP functions can have multiple parameters, and they can also have optional and keyword parameters.
Optional parameters are specified using square brackets, and keyword parameters are specified using &key
followed by a list of key-value pairs.
One of the powerful features of LISP is its support for higher-order functions, which are functions that can
take other functions as arguments or return functions as results. Higher-order functions enable the
implementation of advanced control structures and facilitate the creation of expressive and concise code.
To demonstrate higher-order functions in LISP, let's define a function called apply-twice, which takes a
function f and a value x as arguments and applies f to x twice:
(defun apply-twice (f x)
(funcall f (funcall f x)))
In this example, funcall is used to apply the function f to the value x. The function apply-twice
demonstrates the power of higher-order functions and showcases how they can be used to build more
complex functionality.
In addition to named functions, LISP also allows the creation of anonymous functions using lambda
expressions. Lambda expressions are defined using the lambda special form, followed by a list of
parameters and the body of the function. Here's an example that defines an anonymous function to calculate
the square of a number:
Lambda expressions are commonly used in combination with higher-order functions, allowing for the
creation of ad-hoc functions tailored to specific use cases.
Anonymous functions defined using lambda expressions can be assigned to variables, passed as arguments,
or returned as results, just like named functions. They are particularly useful when we need to define small,
specialized functions within the context of a larger program.
Let's look at an example that demonstrates the use of an anonymous function in combination with a higher-
order function. Consider the following code snippet that uses the map function to apply a given function to
every element of a list:
9
In this example, the square-list function takes a list lst as input and applies an anonymous function
that squares each element of the list using mapcar. The result is a new list containing the squared values.
Features of LISP
1. Symbolic Expression: LISP represents programs and data as symbolic expressions, also known as S-
expressions. These expressions are composed of atoms and lists enclosed in parentheses. For
example:
(+ 2 3)
2. This represents the addition of 2 and 3.
3. Functional Programming: LISP is a functional programming language, meaning it treats
computation as the evaluation of mathematical functions and avoids changing state or mutable data.
Functions are first-class citizens in LISP, meaning they can be passed as arguments to other
functions, returned from functions, and assigned to variables.
4. Dynamic Typing: LISP is dynamically typed, meaning the type of a variable is determined at
runtime rather than compile time. This provides flexibility but may lead to runtime errors if types are
mismatched.
5. Automatic Garbage Collection: LISP implementations typically include automatic garbage
collection, which manages memory allocation and deallocation. This relieves the programmer from
manual memory management tasks and reduces the risk of memory leaks.
6. Symbol Manipulation: LISP excels at symbolic manipulation, making it well-suited for tasks such
as symbolic mathematics, symbolic integration, and theorem proving. It can manipulate its own code
and represent complex symbolic structures easily.
7. Cons Cell and Linked Lists: LISP's fundamental data structure is the cons cell, which consists of
two pointers called car and cdr. Cons cells are used to construct linked lists, trees, and other recursive
data structures efficiently. This simplicity and flexibility contribute to LISP's power.
8. Macros: LISP supports macros, which are transformations of source code that occur before
evaluation. Macros allow programmers to define new syntactic constructs and abstractions, extending
the language to better fit problem domains.
9. Interactive Development: LISP environments typically support interactive development, allowing
programmers to write code and immediately test it in a live environment. This interactive nature
fosters rapid prototyping and experimentation.
10. Extensibility: LISP is highly extensible, allowing programmers to modify the language itself to suit
their needs. This extensibility has led to the development of numerous specialized dialects and
libraries for specific domains.
11. Cross-Platform Compatibility: LISP implementations exist on various platforms, including UNIX-
like systems, Windows, and embedded systems. This cross-platform compatibility enables LISP
programs to run on a wide range of hardware and software environments.
12. Metaprogramming: LISP's homoiconicity—the property that code is represented as data—
facilitates metaprogramming, where programs can manipulate other programs as data. This capability
enables powerful techniques such as code generation, program analysis, and transformation.
13. Historical Significance: LISP has a rich history and has significantly influenced the development of
programming languages and paradigms. Many concepts found in modern languages, such as garbage
collection, higher-order functions, and dynamic typing, were pioneered in LISP.
10
Chapter-3
Program 1 : Family Relations
Objective: The objective of this Prolog program is to implement a simple knowledge base that represents
relationships between family members. The program will define predicates to represent familial relationships
such as parent, sibling, grandparent, etc. Users can then query the knowledge base to get information about
specific relationships within the family.
Code:
% Define gender
male(john).
male(mark).
male(peter).
female(mary).
female(susan).
female(anne).
11
Chapter-4
Program 2 : Simple Student Database in Prolog
Objective: The objective of this Prolog program is to create a simple student database that stores
information about students' names, courses they are enrolled in, and their grades. Users can query the
database to retrieve information about students, courses, and grades.
Code:
12
Chapter-5
Program 3 : Inventory Management System Prolog
Objective: The objective of this Prolog program is to create a basic inventory management system that
keeps track of items in stock, their quantities, and their prices. Users can query the inventory to check the
availability of items, update the quantities, and retrieve information about specific items.
Code:
13
Chapter-6
Program 4 : Task Management System Prolog
Objective: The objective of this Prolog program is to implement a basic task management system that keeps
track of tasks, their priorities, and their statuses. Users can add tasks, mark them as completed, prioritize
them, and query the system for tasks based on various criteria.
Code:
14
Chapter-6
References
1. SWI-Prolog Documentation: [https://www.swi-
prolog.org/pldoc/index.html](https://www.swi-prolog.org/pldoc/index.html)
4. Prolog - Wikipedia:
[https://en.wikipedia.org/wiki/Prolog](https://en.wikipedia.org/wiki/Prolog)
15