App SRM Unit 4 Notes

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 48

Logic programming paradigm

• Logic Programming is the combination of two words, logic and


programming.
• Logic Programming is a programming paradigm in which the
problems are expressed as facts and rules by program statements
but within a system of formal logic.
Facts

• Actually , every logic program needs facts to work with so that it can
achieve the given goal.
• Facts basically are true statements about the program and data.
• For example, Delhi is the capital of India.
Rules
• Rules are the constraints which allow us to make conclusions about
the problem domain. Rules basically written as logical clauses to
express various facts. For example, if we are building any game then
all the rules must be defined.
• Rules are very important to solve any problem in Logic Programming.
Rules are basically logical conclusion which can express the facts.
Following is the syntax of rule −
• A∶− B1,B2,...,Bn. Here, A is the head and B1, B2, ... Bn is the body.
• For example − ancestor(A,B) :- father(A,B).
ancestor(A,C) :- father(A,B), ancestor(B,C).
• This can be read as, for every A and B, if A is the father of B and B is
an ancestor of C, Ais the ancestor of C. For every A and B, A is the
ancestor of C, if A is the father of B and B is an ancestor of C.
Logic programming in python
• For starting logic programming in Python, we need to install the
following two packages −
• Kanren:It provides us a way to simplify the way we made code for
business logic. It lets us express the logic in terms of rules and facts.
The following command will help you install kanren −pip install
kanren
• SymPy:SymPy is a Python library for symbolic mathematics. It aims
to become a full-featured computer algebra system (CAS) while
keeping the code as simple as possible in order to be comprehensible
and easily extensible. The following command will help you install
SymPy −pip install sympy
>>>from kanren import run,var,fact
>>> from kanren.assoccomm import eq_assoccomm as eq
>>> from kanren.assoccomm import commutative,associative
>>> add='add' #Defining operations
>>> mul='mul'
>>> fact(commutative,mul) #Addition and multiplication are commutative and
associative
>>> fact(commutative,add)
>>> fact(associative,mul)
>>> fact(associative,add)
>>> a,b,c=var('a'),var('b'),var('c') #Defining variables
>>> #2ab+b+3c is the expression we have'
>>> expression=(add, (mul, 2, a, b), b, (mul, 3, c))
>>> expression=(add,(mul,3,-2),(mul,(add,1,(mul,2,3)),-1)) #Expression
>>> expr1=(add,(mul,(add,1,(mul,2,a)),b),(mul,3,c)) #Expressions to match
>>> expr2=(add,(mul,c,3),(mul,b,(add,(mul,2,a),1)))
>>> expr3=(add,(add,(mul,(mul,2,a),b),b),(mul,3,c))
>>> run(0,(a,b,c),eq(expr1,expression)) #Calls to run()
First class function
• If a function can be assigned to a variable or passed as object/variable to other function, that function is
called as first class function.
def square(x): return x * x
def cube(x): return x * x * x

def print_result(x, func):


"""recieve a function and execute it and return result"""
return func(x)

do_square = square # assigning square function to a variable


do_cube = cube # assigning cube function to a variable

res = print_result(5, do_square) # passing function to another function


print res
res = print_result(5, do_cube)
print res
Properties of first class functions
• A function is an instance of the Object type.
• You can store the function in a variable.
• You can pass the function as a parameter to another function.
• You can return the function from a function.
• You can store them in data structures such as hash tables, lists etc
Higher order function
• Higher order functions (HOFs) in Python are basically those functions
that take one or multiple functions as an argument or they return a
function as its result..
• We can use nested scopes to create higher-order functions
• We can also use callable objects to create the same
• Using higher-order functions in code the overall code becomes simpler
and shorter.
• Example : map , reduce , filter
Pure functions
• A function is called pure function if it always returns the same result
for same argument values and it has no side effects like modifying an
argument (or global variable) or outputting something.
• The only result of calling a pure function is the return value. Examples
of pure functions are len(), pow(), sqrt() etc.
• Examples of impure functions are rand(), time(), etc.
Kanren

from kanren import run, eq, membero, var, lall


>>> x = var()
>>> run(1, x, eq(x, 5))
(5,)
>> z = var()
>>> run(1, [x, z], eq(x, z),
eq(z, 3))
([3, 4],)
run(1, x, eq((1, 2), (1, x)))
(2,)
>>> run(0, x, membero(x, (1, 2, 3)), # x is a member of (1, 2, 3)
membero(x, (2, 3, 4))) # x is a member of (2, 3, 4)
(2, 3)
Representing knowledge
>>> from kanren import Relation, facts
>>> parent = Relation()
>>> facts(parent, ("Homer", "Bart"),
... ("Homer", "Lisa"),
... ("Abe", "Homer"))

>>> run(1, x, parent(x, "Bart"))


('Homer',)

>>> run(2, x, parent("Homer", x))


('Lisa', 'Bart')
>>> grandparent_lv, parent_lv = var(), var()
>>> run(1, grandparent_lv, parent(grandparent_lv, parent_lv),
parent(parent_lv, 'Bart'))
('Abe’,)
>>> from kanren.constraints import neq, isinstanceo

>>> run(0, x,
... neq(x, 1), # Not "equal" to 1
... neq(x, 3), # Not "equal" to 3
... membero(x, (1, 2, 3)))
(2,)

>>> from numbers import Integral


>>> run(0, x,
... isinstanceo(x, Integral), # `x` must be of type `Integral`
... membero(x, (1.1, 2, 3.2, 4)))
(2, 4)
Sympy
from sympy import *
a = Rational(5, 8)
print("value of a is :" + str(a))
b = Integer(3.579)
print("value of b is :" + str(b))
# import everything from sympy module
from sympy import Symbol,cos
x = Symbol('x’)
e=1/cos(x)
print(e.series(x,0,10))
# import everything from sympy module
from sympy import *
# make a symbol
x = Symbol('x')
# the derivative of sin(x)*e ^ x
ans1 = diff(sin(x)*exp(x), x)
print("derivative of sin(x)*e ^ x : ", ans1)
# Compute (e ^ x * sin(x)+ e ^ x * cos(x))dx
ans2 = integrate(exp(x)*sin(x) + exp(x)*cos(x), x)
print("indefinite integration is : ", ans2)
# Compute definite integral of sin(x ^ 2)dx
# in b / w interval of ? and ?? .
ans3 = integrate(sin(x**2), (x, -oo, oo))
print("definite integration is : ", ans3)
# Find the limit of sin(x) / x given x tends to 0
ans4 = limit(sin(x)/x, x, 0)
print("limit is : ", ans4)
# Solve quadratic equation like, example : x ^ 2?2 = 0
ans5 = solve(x**2 - 2, x)
print("roots are : ", ans5)
PySWIP
• PySwip is a Python - SWI-Prolog bridge enabling to query SWI-Prolog in
your Python programs. It features an (incomplete) SWI-Prolog foreign
language interface, a utility class that makes it easy querying with Prolog
and also a Pythonic interface.
• Since PySwip uses SWI-Prolog as a shared library and ctypes to access it, it
doesn't require compilation to be installed.
• An existing knowledge base stored in a Prolog file can also be consulted
and queried. Assuming the filename "knowledge_base.pl" and the Python is
being run in the same working directory, it is consulted like so:
from pyswip import Prolog
prolog = Prolog()
prolog.consult("knowledge_base.pl")
PySWIP

from pyswip import Prolog


prolog = Prolog()
prolog.assertz("father(michael,john)")
prolog.assertz("father(michael,gina)")
list(prolog.query("father(michael,X)")) == [{'X': 'john'}, {'X': 'gina'}]
for soln in prolog.query("father(X,Y)"):
print(soln["X"], "is the father of", soln["Y"])
# michael is the father of john
# michael is the father of gina
Pydatalog
• pyDatalog adds the logic programming paradigm to Python's toolbox,
in a pythonic way. You can now run logic queries on databases or
Python objects and use logic clauses to define python classes. In
particular, pyDatalog can be used as a query language:
It can perform multi-database queries (from memory datastore, 11
relational databases, and noSQL database with appropriate connectors)
It is more expressive than SQL, with a cleaner syntax;
It facilitates re-use of SQL code snippet (e.g. for frequent joins or
formula);
Datalog

• Datalog = SQL + recursivity


• Datalog is a truly declarative language derived from Prolog, with
strong academic foundations. It complements Python very well for:
managing complex sets of related information (e.g. in data integration
or the semantic web).
simulating intelligent behavior (e.g. in games),
performing recursive algorithms (e.g. in network protocol, code and
graph analysis, parsing)
solving discrete constraint problems.
Example
from pyDatalog import pyDatalog
pyDatalog.create_atoms('parent,bill,ancestor,descendents,manager,first_
remainder, X,Y,Z,N,N1,F, factorial,odd,even, _split, format_’)
+ parent(bill,'John Adams’)
print(parent(bill,X)) # X is 'John Adams’
# specify what an ancestor is
ancestor(X,Y) <= parent(X,Y)
ancestor(X,Y) <= parent(X,Z) & ancestor(Z,Y)
print(ancestor(bill, X)) # X is 'John Adams'
# use expressions and recursion to evaluate factorials
+ (factorial[1] == 1)
(factorial[N] == F) <= (N > 1) & (F == N*factorial[N-1])
print(factorial[3]==N) # N is 6
Dependent type programming
• In computer science and logic, a dependent type is a type whose
definition depends on a value. It is an overlapping feature of type
theory and type systems.
• In intuitionistic type theory, dependent types are used to encode logic's
quantifiers like "for all" and "there exists“
• Two common examples of dependent types are dependent functions
and dependent pairs.
• The return type of a dependent function may depend on the value (not
just type) of one of its arguments.
Dependent type programming(1)
• A dependent pair may have a second value of which the type depends
on the first value.
• a dependent pair may be used to pair an array with its length in a type-
safe way.
• Predicate logic is an extension of propositional logic, adding
quantifiers
• Howard and de Bruijn extended lambda calculus to match this more
powerful logic by creating types for dependent functions, which
correspond to "for all", and dependent pairs, which correspond to
"there exists"
# pylogic for logical validation
# pip install pylogic. It will install logic.py, yacc.py and lex.py in
pylogic module.
import logic
context = logic.Context()
context.assume("[P] and [Q] and [R]")
context.assume("[S] and [T]")
print str(context.validate("[Q] and [S]"))
# prints out "True"
Predicates and Quantifiers
• Predicate logic is an extension of Propositional logic. It adds the
concept of predicates and quantifiers to better capture the meaning of
statements that cannot be adequately expressed by propositional logic.
• The following are some examples of predicates.
Consider E(x, y) denote "x = y"
Consider X(a, b, c) denote "a + b + c = 0"
Consider M(x, y) denote "x is married to y."
The Universal Quantifier
• If p(x) is a proposition over the universe U. Then it is denoted as
∀x,p(x) and read as "For every x∈U,p(x) is true." The quantifier ∀ is
called the Universal Quantifier.
• There are several ways to write a proposition, with a universal
quantifier.
∀x∈A,p(x) or p(x), ∀x ∈A Or ∀x,p(x) or p(x) is true for all
x ∈A.
context = logic.Context()

context.assumePredicate("is a fruit(banana)")
context.assumePredicate("is a fruit(apple)")

context.setTermDomain(["banana", "apple", "carrot"])

print str(context.validate("all x {[is a fruit(x)]}")) # prints False


Existential Quantifier
• If p(x) is a proposition over the universe U. Then it is denoted as ∃x
p(x) and read as "There exists at least one value in the universe of
variable x such that p(x) is true. The quantifier ∃ is called the
existential quantifier.
• There are several ways to write a proposition, with an existential
quantifier, i.e.,
(∃x∈A)p(x) or ∃x∈A such that p (x) or (∃x)p(x) or p(x) is
true for some x ∈A.
context = logic.Context()
# define our predicate function, cast all arguments to ints!
# the validator will stringify them before passing them here
def greater_than(x, y):
return int(x) > int(y)

context.setTermDomain(range(10))
# tell the context about our predicate function, with arity 2
context.setPredicateFunction(greater_than,2)

print str(context.validate("exists x {[greater_than(x,5)]}")) # prints True


Negation of Quantified Propositions
• When we negate a quantified proposition, i.e., when a universally
quantified proposition is negated, we obtain an existentially quantified
proposition,and when an existentially quantified proposition is
negated, we obtain a universally quantified proposition.
• The two rules for negation of quantified proposition are as follows.
These are also called DeMorgan's Law.
• (∃x∈U) (x+6=25):- ≅(∀ x∈U) (x+6)≠25
Dependent function and dependent pairs
• Why universal quantification is represented as a dependent function
type. ∀(x:A).B(x) means “for all x of type A there is a value of type
B(x)”. Hence it's represented as a function which when given any
value x of type A returns a value of type B(x).
• Why existential quantification is represented as a dependent pair type.
∃(x:A).B(x) means “there exists an x of type A for which there is a
value of type B(x)”. Hence it's represented as a pair whose first
element is a particular value x of type A and whose second element is
a value of type B(x).
Network programming
• The term network programming refers to writing programs that execute
across multiple devices (computers), in which the devices are all connected to
each other using a network.
• The various package contains a collection of classes and interfaces that
provide the low-level communication details, allowing you to write programs
that focus on solving the problem
• package provides support for the two common network protocols −
TCP − TCP stands for Transmission Control Protocol, which allows for
reliable communication between two applications. TCP is typically used over
the Internet Protocol, which is referred to as TCP/IP.
UDP − UDP stands for User Datagram Protocol, a connection-less protocol
that allows for packets of data to be transmitted between applications.
• Large amount of Data cannot be transferred at once, so it is divided
into manageable pieces called frames or packets
• All the frames are send to receiver one by one.
• If all the frames travel through a common path, this type of
transmission is known as Connection Oriented. Ex. A: D:B
• All the packets will be sent to D by node B.
• If all the frames travel through a random path, this type of
transmission is known as Connectionless. Ex. A: D:NIL
• All the packets will be sent to D by and middle node.
Sockets
• Sockets and the socket API are used to send messages across a network.
They provide a form of inter-process communication (IPC). The network
can be a logical, local network to the computer, or one that’s physically
connected to an external network, with its own connections to other
networks. The obvious example is the Internet, which you connect to via
your ISP.
• Sockets are the endpoints of a bidirectional communications channel.
Sockets may communicate within a process, between processes on the same
machine, or between processes on different continents.
• Sockets may be implemented over a number of different channel types:
Unix domain sockets, TCP, UDP, and so on.
• The socket library provides specific classes for handling the common
transports as well as a generic interface for handling the rest.
Socket Programming
• Sockets provide the communication mechanism between two computers
using TCP. A client program creates a socket on its end of the
communication and attempts to connect that socket to a server.
• When the connection is made, the server creates a socket object on its end of
the communication. The client and the server can now communicate by
writing to and reading from the socket.
• TCP almost always uses SOCK_STREAM and UDP uses SOCK_DGRAM.
• TCP (SOCK_STREAM) is a connection-based protocol. The connection is
established and the two parties have a conversation until the connection is
terminated by one of the parties or by a network error.
• UDP (SOCK_DGRAM) is a datagram-based protocol. You send one
datagram and get one reply and then the connection terminates.
Socket Programming(1)
• If you send multiple packets, TCP promises to deliver them in order.
UDP does not, so the receiver needs to check them, if the order
matters.
• If a TCP packet is lost, the sender can tell. Not so for UDP.
• UDP datagrams are limited in size, from memory I think it is 512
bytes. TCP can send much bigger lumps than that.
• TCP is a bit more robust and makes more checks. UDP is a shade
lighter weight (less computer and network stress).
Python - Network Programming
• Python provides two levels of access to network services.
At a low level, you can access the basic socket support in the
underlying operating system, which allows you to implement clients
and servers for both connection-oriented and connectionless protocols.
Python also has libraries that provide higher-level access to specific
application-level network protocols, such as FTP, HTTP, and so on.
The socket Module
• To create a socket, you must use the socket.socket() function available
in socket module, which has the general syntax −
s = socket.socket (socket_family, socket_type, protocol=0)
• Here is the description of the parameters −
socket_family − This is either AF_UNIX or AF_INET, as explained earlier.
socket_type − This is either SOCK_STREAM or SOCK_DGRAM.
protocol − This is usually left out, defaulting to 0.
• Once you have socket object, then you can use required functions to create
your client or server program. Following is the list of functions required −
Server Socket Methods
Client Socket Methods
General Socket Methods
TCP Sockets

• Create a socket object using socket.socket() and specify the socket


type as socket.SOCK_STREAM. When you do that, the default
protocol that’s used is the Transmission Control Protocol (TCP).
• Why should you use TCP? The Transmission Control Protocol (TCP):
Is reliable: packets dropped in the network are detected and
retransmitted by the sender.
Has in-order data delivery: data is read by your application in the
order it was written by the sender.
• In contrast, User Datagram Protocol (UDP) sockets created with
socket.SOCK_DGRAM aren’t reliable, and data read by the receiver
can be out-of-order from the sender’s writes.
• Why is this important? Networks are a best-effort delivery system.
There’s no guarantee that your data will reach its destination or that
you’ll receive what’s been sent to you.
• Network devices (for example, routers and switches), have finite
bandwidth available and their own inherent system limitations. They
have CPUs, memory, buses, and interface packet buffers, just like our
clients and servers. TCP relieves you from having to worry about
packet loss, data arriving out-of-order, and many other things that
invariably happen when you’re communicating across a network.
Socket Programming in Python
• To write Internet servers, we use the socket function available in
socket module to create a socket object.
• A socket object is then used to call other functions to setup a socket
server.
• Now call bind(hostname, port) function to specify a port for your
service on the given host.
• Next, call the accept method of the returned object. This method waits
until a client connects to the port you specified, and then returns
a connection object that represents the connection to that client.
A Simple Client

• Let us write a very simple client program which opens a connection to


a given port 12345 and given host. This is very simple to create a
socket client using Python's socket module function.
• The socket.connect(hosname, port ) opens a TCP connection
to hostname on the port. Once you have a socket open, you can read
from it like any IO object. When done, remember to close it, as you
would close a file.
• The following code is a very simple client that connects to a given
host and port, reads any available data from the socket, and then exits

• Now run this server.py in background and then run above client.py to
see the result.

You might also like