Статья Введение в основные принципы логического программирования [часть 1]

29675


Всем привет!

Команда форума подготовила для вас перевод одной очень интересной статьи -> . Приятного чтения! :)


Логи́ческое программи́рование — парадигма программирования, основанная на автоматическом доказательстве теорем, а также раздел дискретной математики, изучающий принципы логического вывода информации на основе заданных фактов и правил вывода.(c)Wikipedia

Прежде чем мы поговорим о том, что это такое, и как это относится к искусственному интеллекту, давайте немного поговорим о парадигмах программирования.

Отступление от 5h3ll:

Парадигма программирования, определяет то, как вы будете подходить к решению проблемы. Тут не существует плохой, правильной или не правильной парадигмы, проще всего подобные абстракции, объясняются на примерах из реальной жизни.

Например есть Коля и Петя. Коля строит небольшие сараи на участках, и ход его работ прост, прямолинеен и понятен. Он просто выполняет определенное действие в нужном ему порядке. По сути коля строит сарай используя процедуральную парадигму программирования, причина тому проста — он делал это 1000 раз и тратить время на бесполезное планирование(время деньги) смысла нет.

С другой стороны его друг Петя строит небоскребы в Moscow-City и руководит большим штатом рабочих: архитекторов, юристов, строителей и тд. Понятное дело, что такая большая схема будет крайне неповоротлива, если исполнять все по пунктам. Проблема в том, что пока одно звено не закончит свою функцию — последующее не начнет работу, а это простои работы, финансовые потери ну, и как результат - недовольные инвесторы. Потому лучший выбор для Пети — это: ООП, где все объекты(классы) будут структурированы, заниматься каждый своим делом и в то же время взаимодействовать друг с другом по мере необходимости.
Так что, как мы видим, для каждой проблемы лучше использовать подходящую парадигму.


Вот некоторые из наиболее популярных парадигм программирования:
  • Imperative: в этой парадигме используются операторы для изменения состояния программы, что позволяет учитывать побочные эффекты.
  • Functional: эта парадигма рассматривает вычисления как оценку математических функций и не позволяет изменять состояния или изменяемые данные.
  • Declarative: это способ программирования, при котором вы пишете свои программы путем описывания, что именно вы хотите сделать, а не как вы хотите это сделать. Вы выражаете логику базовых вычислений без явного описания потока управления.
  • Object Oriented: в этой парадигме код группируется в программе таким образом, что каждый объект отвечает за себя. Объекты содержат данные и методы, которые определяют, каким именно образом происходят изменения.
  • Procedural: в этой парадигме код группируется по функциям, и каждая функция отвечает за определенную последовательность шагов.
  • Symbolic: в этой парадигме используется особый стиль синтаксиса и грамматики, с помощью которого программа может изменять свои собственные компоненты, рассматривая их как простые данные.
  • Logic: в этой парадигме вычисления рассматриваются как автоматическое обоснование базы данных знаний, состоящей из фактов и правил.
Чтобы понять логическое программирование, давайте разберемся с понятиями вычислений и дедукций. Чтобы что-то вычислить, мы начнем с выражения и набора правил. Этот набор правил в основном программа. Мы используем эти выражения и правила для генерации вывода.

Например, мы хотим вычислить сумму 23, 12 и 49:

https://cdn-images-1.medium.com/max/1600/0*EWIW0TiQwaGk_T1C.jpg


Процедура будет выглядеть следующим образом:
Код:
23 + 12 + 49 => (2 + 1 + 4 + 1)4 => 84
С другой стороны, если мы хотим что-то сделать, нам нужно начать с гипотезы. Затем нам нужно построить доказательство в соответствии с набором правил. По сути, процесс вычисления является
механическим, тогда как процесс дедукции более творческий. Когда мы пишем программу в логической парадигме программирования, мы указываем набор утверждений,
основанных на фактах и правилах о проблемной области, и решающая программа решает ее, используя эту информацию.

Понимание составных элементов логического программирования

При программировании объектно-ориентированных или императивных парадигм мы всегда должны указывать, как определяется переменная. В логическом программировании все работает немного иначе.

Мы можем передать неопределенный аргумент функции, и интерпретатор припишет значение этих переменных для нас, взглянув на факты, определенные пользователем. Это мощный способ решения проблемы соответствия переменных. Процесс сопоставления переменных с различными элементами называется унификацией. Это одно из мест, где логическое программирование действительно находится в стороне.

Нам нужно указать то, что называется связи/отношения в логическом программировании. Эти связи определяются с помощью положений, называемых фактами и правилами.

Факты - это просто утверждения, которые являются правдой о нашей программе и данных, с которыми она работает. Синтаксис довольно прост. Например, Дональд - сын Аллана, может быть фактом, тогда как, Кто сын Аллана? не может быть фактом.
Каждая логическая программа нуждается в фактах для работы, чтобы она могла достичь поставленной цели на их основе.
Правила - это та информация, которую мы узнали о том каким образом выражать различные факты и как их запрашивать. Это те ограничения, с которыми нам приходится работать, и они позволяют нам делать выводы о проблемной области.
Например, допустим, вы работаете над созданием шахматного движка. Вам нужно указать все правила о том, как каждая фигура может двигаться на шахматной доске. По сути, окончательный вывод действителен только в том случае, если все отношения/связи верны.

Решение проблем с помощью логического программирования

Логическое программирование ищет решения, используя факты и правила. Нам нужно указать цель для каждой программы. В случае, когда логическая программа и цель не содержат каких-либо переменных,
решающая программа создает дерево, которое представляет собой пространство поиска для решения проблемы и достижения цели.
Одна из самых важных вещей в логическом программировании - это то, как мы относимся к правилам. Правила можно рассматривать как логические утверждения. Давайте рассмотрим следующее:
Код:
Кэти любит шоколад => Александр любит Кэти
Это можно прочитать как подтекст, который говорит: если Кэти любит шоколад, то Александр любит Кэти. Это также может быть истолковано как то, что Кэти любит шоколад подразумевает, что Александр любит Кэти.
Аналогично, давайте рассмотрим следующее правило:
Код:
Криминальные фильмы, английский язык => Martin Scorsese
Это может быть прочитано следующим образом: Если вам нравятся криминальные фильмы на английском языке, то вам понравятся фильмы, снятые Мартином Скорсезе.
Эта конструкция используется в различных формах в логическом программировании для решения различных типов задач. Давайте продолжим и посмотрим, как решить эти проблемы в Python.

Установка пакетов Python

Прежде чем мы начнем логическое программирование на Python, нам нужно установить пару пакетов. Пакет logpy - это пакет Python, который делает доступным логическое программирование на Python.
Мы также будем использовать sympy для решения некоторых проблем. Итак, давайте установим logpy и sympy с помощью pip:
Python:
$ pip3 install logpy
$ pip3 install sympy
Согласование математических выражений

Мы постоянно сталкиваемся с математическими операциями. Логическое программирование - это очень эффективный способ сравнения выражений и обнаружения неизвестных значений. Давайте посмотрим, как это сделать.

Создайте новый файл Python и импортируйте следующие пакеты:
Python:
from logpy import run, var, fact
import logpy.assoccomm as la
Определите пару математических операций:
Python:
add = 'addition'
mul = 'multiplication'
И сложение, и умножение являются коммутативными операциями. Давайте определим их, а именно:
Python:
fact(la.commutative, mul)
fact(la.commutative, add)
fact(la.associative, mul)
fact(la.associative, add)
Давайте определим некоторые переменные:
Python:
a, b, c = var('a'), var('b'), var('c')
Рассмотрим следующее выражение:
Код:
expression_orig = 3 x (-2) + (1 + 2 x 3) x (-1)
Сгенерируем это выражение с замаскированными переменными.

Первое выражение:
Код:
expression1 = (1 + 2 x a) x b + 3 x c
Второе выражение:
Код:
expression2 = c x 3 + b x (2 x a + 1)
Третье выражение:
Код:
expression3 = (((2 x a) x b) + b) + 3 x
Если вы достаточно внимательны, вы заметите, что все три выражения представляют одно и то же основное выражение.
Наша цель - сопоставить эти выражения с исходным выражением для извлечения неизвестных значений:
Python:
expression_orig = (add, (mul, 3, -2), (mul, (add, 1, (mul, 2, 3)), -1))
expression1 = (add, (mul, (add, 1, (mul, 2, a)), b), (mul, 3, c))
expression2 = (add, (mul, c, 3), (mul, b, (add, (mul, 2, a), 1)))
expression3 = (add, (add, (mul, (mul, 2, a), b), b), (mul, 3, c))
Сравните выражения с исходным выражением. Данный метод обычно используется в logpy. Этот метод принимает входные аргументы и выполняет выражение.
Первый аргумент - это число значений, второй аргумент - это переменная, а третий аргумент - это функция:
Python:
print(run(0, (a, b, c), la.eq_assoccomm(expression1, expression_orig)))
print(run(0, (a, b, c), la.eq_assoccomm(expression2, expression_orig)))
print(run(0, (a, b, c), la.eq_assoccomm(expression3, expression_orig)))
Полный код предоставлен в expression_matcher.py. Если вы запустите код, вы увидите следующий вывод в своем терминале:
Python:
((3, -1, -2),)
((3, -1, -2),)
()
Три значения в первых двух строках представляют собой значения для a, b и c. Первые два выражения совпадают с исходным выражением, а третье ничего не возвращает.

Причина в том, что хоть третье выражение математически одинаково, оно структурно отличается. Сравнение шаблонов работает путем сравнения структуры выражений.

29676
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!