Этой статьей я начинаю серию публикаций, посвященных проблеме программирования искусственного интеллекта. Цель этого цикла - показать, каким образом (в смысле общих принципов) осуществляется программирование искусственного интеллекта.
Само понятие "искусственный интеллект" возникло где-то на заре вычислительной техники. Несмотря на почтенный возраст, термин этот не имеет точного определения и всегда понимался в интуитивном смысле. Обычно говорят, что к области искусственного интеллекта относятся те задачи, которые до сих пор человек решает лучше, чем компьютер. Таким образом, круг решаемых в рамках искусственного интеллекта проблем постоянно динамически изменяется. Например, еще несколько лет назад обучение ЭВМ игре в шахматы являлось прерогативой AI (от английского Artifical Intelligence - искусственный интеллект), но сегодня все больше специалистов считает, что игра в шахматы уже не является проблемой искусственного интеллекта. Сегодня главными проблемами, решаемыми в рамках AI, являются примерно следующие: построение экспертных систем, решение задач поиска, в которых полный перебор вариантов теоретически невозможен (в том числе - программирование игр), моделирование биологических форм, распознавание образов. Фундаментальные принципы решения всех этих задач были заложены еще в начале семидесятых, но, в связи с тем, что задачи AI очень ресурсоемки, настоящее развитие они получили только в наши дни.
Для решения задач AI еще в начале семидесятых годов были созданы два специфических языка программирования - Пролог (Prolog) и Лисп (LISP). Современный разработчик искусственного интеллекта должен свободно владеть каждым из них. Далее остановимся на самых характерных их особенностях.
Исторически Лисп более старый язык. Концепция, которую он представляет, называется функциональным программированием, она является прямым продолжением обычного алгоритмического подхода. Лисп-программа представляет собой функцию, результат вычисления которой - это результат работы программы, а аргументы, чаще всего - другие вызовы функций. В связи с объективными причинами в Лиспе принята бесскобочная запись при вызове функций, вызов любой функции осуществляется при помощи списка, первым элементом которого является название функции, а все остальные элементы представляют аргументы. Например, сложение двух чисел A и B может выглядеть так : (add A B), сложение трех чисел - так : (add A (add B C)). Самой важной особенностью Лиспа является то, что запись вида (add A B) может представлять из себя не только список, как вызов функции, но и список, как элемент данных, содержащий в себе три компоненты - add, A и B. Решение о том, следует ли использовать список как данные, или его необходимо интерпретировать, в рамках Лиспа может приниматься самой программой. Таким образом, программа получает возможность модифицировать собственный код, что чрезвычайно важно для приложений AI.
Пролог для меня более интересен, чем Лисп, поскольку использует подход к программированию, принципиально отличный от алгоритмического и называемый целевым или декларативным программированием. При алгоритмическом программировании мы задаем последовательность действий, которые должна выполнять программа, т.е. описываем, КАК она должна работать. При декларативном программировании мы описываем, ЧТО программа должна делать, а то, как будут осуществлены эти действия - дело Пролог-системы. Рассмотрим типичнейшую Пролог-задачу - определение, в каких родственных отношениях находятся те или иные люди. В качестве исходных выберем отношение родитель(X,Y), обозначающее, что X является родителем Y, и отношения мужчина(X) и женщина (X), обозначающие принадлежность лица к одному из полов. Тогда исходные данные для программы могут выглядеть примерно так.
мужчина(Сергей). женщина(Тамара). мужчина(Семен). женщина (Людмила). мужчина(Павел).
родитель(Сергей, Семен). родитель(Тамара, Семен). родитель(Семен, Павел).
родитель(Людмила, Павел)
Как можно видеть, это - небольшая база данных, естественно представляющая генеалогическое дерево. Каждое из выражений в ней является утверждением, в Прологе такие утверждения называют фактами. База может быть легко расширена.
Теперь введем выражение дед(X,Y), обозначающее, является ли X дедом Y. Мы используем два Прологовских символа - запятая в следующей записи обозначает логическое и, а символ :- обозначает если.
дед(X,Y):- родитель(X,Z), родитель(Z,Y),мужчина(X).
Эта условная запись является таким же элементом базы данных, как и факты, в Прологе такие элементы принято называть правилами.
На самом деле та Пролог-программа, которую мы написали, умеет делать очень многое (это наверняка удивит тех, кто до сих пор был знаком только с алгоритмическим программированием). После запуска ее на выполнение Пролог-система выдаст запрос на ввод вопроса. Для начала введем дед(X,Павел) (по-русски этот вопрос звучит так: "Кто дед Павла?"), система выдаст X=Сергей. Теперь спросим дед(Тамара, Павел) ("Является ли Тамара дедом Павла?"). Получим ответ no (нет). Можно спросить родитель(X,_) (так, как на Прологе _ обозначает, что значение этого элемента отношения для нас не важно, то данная запись по-русски звучит, как "Кто является чьим-либо родителем?"). Получим X=Сергей, X=Тамара, X=Семен, X=Людмила. Этим круг вопросов, которые можно задать нашей программе, далеко не исчерпывается.
Как видим, в задачах, связанных с заданием отношений между объектами, Пролог гораздо мощнее алгоритмических языков типа Паскаля или Си. Если добавить к этому, что база данных Пролога (содержащая факты и правила) может динамически изменяться во время выполнения самой же программой или пользователем, становится ясно, насколько полезен Пролог для разработки в области искусственного интеллекта.
Если читателя заинтересовали Лисп и Пролог, он может изучить их самостоятельно - языки очень просты. Я же в последующих публикациях не буду останавливаться на лингвистических проблемах, стараясь уделить внимание только фундаментальным методам программирования в области AI.
Денис МАРГОЛИН
[email protected]
![Версия для печати Версия для печати](https://www.kv.by/sites/all/modules/print/icons/print_icon.png)
Горячие темы