Tutorials > Logic Programming for Artificial Intelligence in Python

Logic Programming for Artificial Intelligence in Python

Introduction

To accomplish the above, we will spend this chapter in studying the functional and logic programming using Python. These are theories based off AI Programming that form the basis of code which learns from patterns and rules. Logic Programming talks about the study of principles that orbit across establishment of reasoning within tasks. It is the analysis of present rules, using which future outcomes can be derived. For instance, if three statements are resulting in a ‘True’ answer, the program can infer the output of a fourth related statement.

Idea Description

As the words suggest, Logic Programming is combined of two distinct ideas – logic and programming. Logic here details the facts and rules that the programming structure needs to understand. A logical approach to programming requires a set of input rules that the code learns and then infers an output on a new related fact it has not seen before. This can also be viewed as a form of a learning algorithm with an explicit instruction of understanding.

What is Logic Programming?

Writing code in Python, C, C++, Java, etc. we have observed paradigms like object-oriented programming (OOPS), abstraction, looping constructs and numerous other states of programming. Logic Programming is just another programming paradigm that works on relationships. These relationships are built using facts and rules and are stored as a database of relations. It is a programming methodology that works on formal and explicit logic of events.
Relation:Relations are the basis of logic programming. A relation can be defined as a fact that follows a certain rule. For example, a relation given by [ A -> B ] is read as “if A is true, then B occurs”. In language terms, this can be read as, “If you are an Engineer, then you are a Graduate” and infers that, “Engineers are Graduates”. In programming languages, the semantics of writing relations changes based on the language’s syntax, but this is the overall rationality behind what relations mean.
Facts: Every program that is built on logic needs facts. To achieve a defined goal, facts need to be provided to the program. As the name suggests in general English, facts are merely the truth. True statements that represent the program and the data. For instance, Washington is the capital of the United States of America.
Rules: Rules, like programming syntax are the constraints that help in drawing conclusions from a domain. These are logical clauses that the program or the fact needs to follow to build a relation. You can think of it like this, a fact is that Raman is a man. Now, gender can be a singular entity, that is a rule. A man cannot be a woman. Therefore, the relations we build here are that, since Raman is a man, he cannot be a woman. This is how rules are built:
For example: predecessor(A,B) :- parent(A,B).
predecessor(A,C) :- parent(A,B), predecessor(B,C).
This can be read as, for every A and B, if A is the parent of B and B is a predecessor of C, A is the predecessor of C. For every A and B, A is the predecessor of C, if A is the parent of B and B is a predecessor of C.
1.png

Use Cases of Logic Programming

  1. Logic Programming is extensively used in Natural Language Processing (NLP) since understanding languages is about recognition of patterns that numbers cannot represent.
  2. It is also used in prototyping models. Since expressions and patterns can be replicated using logic, prototyping is made easy.
  3. Pattern matching algorithms within image processing, speech recognition and various other cognitive services also use logic programming for pattern recognition.
  4. Scheduling and Resource Allocation are major operations tasks that logic programming can help solve efficiently and completely.
  5. Mathematical proofs are also easy to decode using logic programming.

Solving Puzzles using Artifical Intelligence

Logic Programming can be used to solve numerous mathematical problems that will ultimately help in building an artificially intelligent machine. In the sections coming next, we will observe how Logic Programming can be used to evaluate expressions in mathematics, make programs learn operations and form predictions. We will also solve a real problem using two libraries that influence logic programming in Python.
Kanren: Kanren is a library within PyPi that simplifies ways of making business logic out of code. The logic, rules, and facts we discussed previously can be turned into code using ‘kanren’. It uses advanced forms of pattern matching to understand the input expressions and build its own logic from the given input. We will be using this library in the sections below for mathematical computations. The import and installation steps are mentioned in the code section that follows.
SymPy: SymPy stands for symbolic computation in Python and is an open-sourced library. It is used for calculating mathematical constructs using symbols. The aim of the SymPy project is to establish a completely featured Computer Algebra System (CAS). The aim here is to keep the understanding of the code simple and comprehensive.

# Run the below command to install kanren. It does not come pre-installed with the Anaconda distribution of Jupyter Notebook. You will see an installation like below.

pip install kanren


>>> 
Collecting kanren
  Downloading kanren-0.2.3.tar.gz (23 kB)
Collecting unification
  Downloading unification-0.2.2-py2.py3-none-any.whl (10 kB)
Building wheels for collected packages: kanren
  Building wheel for kanren (setup.py): started
  Building wheel for kanren (setup.py): finished with status 'done'
Installing collected packages: unification, kanren
Note: you may need to restart the kernel to use updated packages.
Successfully installed kanren-0.2.3 unification-0.2.2


# Once kanren is installed to the Jupyter Notebook kernel, run the below command to install sympy. All required components of the sympy collection will get installed

pip install sympy

With this installation, we are now ready to implement the above packages to work with Logic Programming in the Python language. Let us start by calculating some math functions.

Evaluating Mathematical Idioms using Logic Programming

Algorithms are nothing but implementation of logic and control. Similarly, when the logic runs a mathematical function, we call it a mathematical expression. These expressions are the inputs we give to the program, based on which the program understands the rules that are present in the logic. Based on the understanding of these rules, future expressions can also be evaluated. Let us see an implementation of Logic Programming to evaluate mathematical expressions:

# Import the necessary functions from the kanren library
from kanren import run, var, fact
from kanren.assoccomm import eq_assoccomm as eq
from kanren.assoccomm import commutative, associative
# Define values that will undertake the addition and multiplication operations
addition = 'add'
multiplication = 'mul'
# Define facts and properties of each operation
fact(commutative, multiplication)
fact(commutative, addition)
fact(associative, multiplication)
fact(associative, addition)
# Declare the variables that are going to form the expression
var_x, var_y, var_z = var('var_x'), var('var_y'), var('var_z')
# Build the correct pattern that the program needs to learn
match_pattern = (addition, (multiplication, 4, var_x, var_y), var_y, (multiplication, 6, var_z))
match_pattern = (addition, (multiplication, 3, 4), (multiplication, (addition, 1, (multiplication, 2, 4)),2))

# Build 3 distinct expressions to test if the function has learnt
test_expression_one = (addition, (multiplication, (addition, 1 , (multiplication, 2, var_x )), var_y) ,(multiplication, 3, var_z )) 
test_expression_two = (addition, (multiplication, var_z, 3), (multiplication, var_y, (addition, (multiplication, 2, var_x), 1)))
test_expression_three = (addition  , (addition, (multiplication, (multiplication, 2, var_x), var_y), var_y), (multiplication, 3, var_z))
# Test the evaluations of the expression on the test expressions
run(0,(var_x,var_y,var_z),eq(test_expression_one,match_pattern))


>>> ((4, 2, 4),)


run(0,(var_x,var_y,var_z),eq(test_expression_two,match_pattern))


>>> ((4, 2, 4),)


print(run(0,(var_x,var_y,var_z),eq(test_expression_three,match_pattern)))


>>> ( )


# Since the first two expressions satisfy the expression above, they return the values of individual variables. The third expression is structurally different and therefore does not match

# Running Mathematical Evaluations using SymPy
import math
import sympy
print (math.sqrt(8))


>>> 2.8284271247461903


# Although the Math Square Root function gives an output for the Square Root of 8, we know this is not accurate since the square root of 8 is a recursive, non-ending real number
print (sympy.sqrt(3))


>>> sqrt(3)


# Sympy on the other hand, symbolizes the output and shows it as root of 3
# In case of actual square roots like 9, SymPy gives the correct result and not a symbolic answer

These were a few basic use cases that utilize the libraries mentioned for logic programming. We will closely be working on these concepts during the Natural Language Processing (NLP) and Speech Recognition portions of this series of tutorials. Let us know try solving for Prime numbers using Python.

# Import the necessary libraries for running the Prime Number function
from kanren import membero, isvar, run
from kanren.core import goaleval, condeseq, success, fail, eq, var
from sympy.ntheory.generate import isprime, prime
import itertools as iter_one

# Defining a function to build the expression
def exp_prime (input_num): 
    if isvar(input_num):
        return condeseq([(eq, input_num, x)] for x in map(prime, iter_one.count(1)))
    else:
        return success if isprime (input_num) else fail

# Variable to use
n_test = var() 
set(run(0, n_test,(membero, n_test,(12,14,15,19,21,20,22,29,23,30,41,44,62,52,65,85)),( exp_prime, n_test)))



>>> {19, 23, 29, 41}


run(7, n_test, exp_prime(n_test))


>>> (2, 3, 5, 7, 11, 13, 17)

The implementation of Logic Programming in Python has enabled programmers to directly run mathematical operations in code. Numerous applications that we discussed earlier as use cases are built on Logic Programming and we will be using this in the coming chapters. Let us now move to another paradigm that is important for creating artificially intelligent machines, namely Functional Programming.

Functional Programming in Python

Functional Programming is another declarative approach to writing code that focuses on ‘What needs to be solved’ more than ‘how to solve’. It uses expressions to build code instead of using statements. Solving expressions gives values and computing statements assings variables. Functional Programming has the following concepts:
  1. Pure Functions: These are straight result-oriented functions. The idea here is to always produce the same output if the input has same arguments, regardless of any other conditions in the code. Also, pure functions do not have any effects on the code. They do not modify global variables or arguments.
  2. Recursion: Functional Programming does not have any implementation of control looping structures like ‘while’ and ‘for’ loops. All iterations are computed using recursion in FP.
  3. First Class and High Order Functions: All first-class variables of a functional portion of code can be passed as arguments to first-class functions. These parameters can then be stored within data structures that the function will use or be returned to function’s output.
  4. Immutable Variables: After their initialization, functional program variables cannot be modified. Although, creation of new variables is always possible.

# Working with Pure Functions in Python
# Pure functions do not change the input list
def pure_func(List): 
    Create_List = [] 
    for i in List: 
        Create_List.append(i**3) 
    return Create_List 
# Test input code
Initial_List = [1, 2, 3, 4] 
Final_List = pure_func(Initial_List) 
print("The Root List:", Initial_List) 
print("The Changed List:", Final_List)



>>> The Root List: [1, 2, 3, 4]
>>> The Changed List: [1, 8, 27, 64]


# Looking at Recursion code in Python
# We implement Recursion to find the sum of a list
def Sum(input_list, iterator, num, counter): 
    if num <= iterator: 
        return counter 
    counter += input_list[iterator] 
    counter = Sum(input_list, iterator + 1, num, counter) 
    return counter 
# Driver's code 
input_list = [6, 4, 8, 2, 9] 
counter = 0
num = len(input_list) 
print(Sum(input_list, 0, num, counter))



>>> 29


# Python demonstration of high-order functions
def func_shout(text_input): 
    return text_input.upper() 
def func_whisper(text_input): 
    return text_input.lower() 
def greet(func_var): 
    # Store the Function as a variable 
    greet_text = func_var("Hello, I was passed like an argument to a function") 
    print(greet_text) 
greet(func_shout) 
greet(func_whisper)



>>> HELLO, I WAS PASSED LIKE AN ARGUMENT TO A FUNCTION
>>> hello, i was passed like an argument to a function

Some Key High-Order Functions: In order to implement the computing of iterable objects like lists, dictionaries, tuples, etc. functional programming uses some high-order predefined functions. Let us see their implementations below:
  • Map(): The Map() function in Python returns a list of results as output after applying the given function to every individual item of the iterable.
  • Filter(): The filter function is a boolean checker that passes every element within the iterable through a check defined within the input function.
  • Lambda Functions: Anonymous functions in Python are those that do not have a name. The ‘lambda’ keyword is used instead of the ‘def’ keyword to define these functions.


# Implementation of Map() in Python
def addition(num): 
    return num + num
# Implement the function of doubling input numbers
input_numbers = (3, 4, 1, 2) 
final_results = map(addition, input_numbers) 
# This print statment would not return results, and only show the object type
print(final_results) 
# This will return results
for num_result in final_results: 
    print(num_result, end = " ")
    


>>>
>>> 6 8 2 4

# Python implementation of Filter() function
# Writing a function to filter vowels 
def Check_Vowel(var): 
    vowels = ['a', 'e', 'i', 'o', 'u'] 
    if (var in vowels): 
        return True
    else: 
        return False
test_seq = ['m', 'a', 'i', 'x', 'q', 'd', 'e', 'k'] 
filter_output = filter(Check_Vowel, test_seq) 
print('The extracted vowels are:') 
for s in filter_output: 
    print(s)
    


>>> The extracted vowels are:
>>> a
>>> i
>>> e



# Writing a lambda function in Python
result_cube = lambda a: a * a*a 
print(result_cube(8)) 
test_list = [4, 2, 1, 3, 5, 6] 
even_test = [a for a in test_list if a % 2 == 0] 
print(even_test)



>>> 512
>>> [4, 2, 6]

 

Importance of Functional and Logic Programming for AI

Functional Programming stands out in making programs fault tolerant and quick for critical and lengthy calculations which in return makes the decision-making process simpler. This fault tolerance and rapid decision formation makes Functional Programming important for Artificial Intelligence. Although at present, it is not being used to its potential, in future FP could make self-driving cars more reliable, secure, and safe. In any scenario that involves human/animal life, a systematic failure could have adverse negative effects. Immutability as a concept within Functional Programming makes the entire system more reliable to faults. Lazy Evaluation helps in conserving memory and therefore making processes efficient. Parallel Programming makes machines faster. The notion of being able to pass functions as arguments to other functions, creates more possibilities and increases overall functionality. All these features of FP make it a solid fit for Artificial Intelligence.

Logic Programming on the other hand, helps AI agents in performing calculations that are repetitive and occur often, this allows driving analytics from these calculations. Inferential Analysis, properties of a language, erasing the gap between high-level logical analysis and its subsequent implementation with ease, are few use cases where logic programming enhances the features of AI based algorithms. Logic based code is a declarative programming approach that focuses on making code look like reading English. Artificial Intelligence is a conceptual implementation of machines that makes them mimic human intelligence. Logic programming gives these machines the power of reasoning, that in return allows for making the inferences like humans.

Coming Up Next

This tutorial was meant to touch base with Logic Programming, Functional Programming, and their respective importance in the enhancement of AI algorithms. There are multiple advanced examples of use between these programming paradigms that are often used in group theory, natural language processing, etc. In the coming chapters we will dive deep into Logic Programming for cognitive science algorithms. Below are some topics we will be covering in the coming chapters:
  1. Natural Language Processing
  2. Tokenization, Stemming and Lemmatization
  3. Text Mining