- •Глава 1
- •Искусственный интеллект
- •Фактуальное и операционное знание
- •Признаки иис
- •Системы с интеллектуальным интерфейсом
- •Экспертные системы
- •Самообучающиеся системы
- •Адаптивные информационные системы
- •Языки программирования для ии и языки представления знаний
- •Глава 2
- •Данные и знания
- •Модели представления знаний
- •Глава 3
- •Системы продукций
- •Стратегии поиска в пространстве состояний
- •Рекурсивный поиск
- •Глава 4
- •Введение в экспертные системы. Определение и структура
- •Классификация экспертных систем
- •Коллектив разработчиков
- •Технология проектирования и разработки
- •Глава 5
- •Поле знаний
- •Стратегии получения знаний
- •Теоретические аспекты извлечения знаний
- •Теоретические аспекты структурирования знаний
- •Технологии инженерии знаний
- •Глава 6
- •Задача классификации
- •Деревья решений
- •Искусственные нейронные сети
- •Глава 7
- •Способы аналитической обработки данных
- •Некоторые бизнес-приложения Data Mining
- •Типы закономерностей
- •Процесс нахождения нового знания
- •Глава 1 2
- •Глава 2 15
- •Глава 3 23
- •Глава 4 45
- •Глава 5 54
- •Глава 6 62
- •Глава 7 88
Рекурсивный поиск
О реализации поиска в пространстве состояний
Ранее были рассмотрены различные методы поиска в пространстве состояний. Этот подход «пространства состояний» к решению задачи позволяет использовать теорию графов для создания и анализа компьютерных программ. Был определен общий алгоритм поиска с возвратами, алгоритмы поиска в глубину и в ширину, а также эвристический поиск. Следующие понятия характеризуют данные и управляющие структуры, используемые для реализации поиска в пространстве состояний.
Представление решения задачи в виде пути от начального состояния к целевому.
Алгоритм поиска, систематически проверяющий наличие альтернативных путей к цели.
Поиск с возвратами или другой механизм, позволяющий выходить из тупиковых состояний и находить путь к цели.
Списки, содержащие точную информацию о рассматриваемых в данный момент состояниях, в том числе:
список open, позволяющий алгоритму в случае необходимости исследовать ранее не рассмотренные состояния;
список closed, содержащий рассмотренные состояния, позволяющий алгоритму избегать зацикливаний и учитывать тупиковые пути.
Список open можно рассматривать как стек для поиска в глубину, очередь для поиска в ширину или приоритетную очередь для «жадного» алгоритма поиска.
В данном разделе вводится и рассматривается рекурсивный поиск, определяющий поиск в глубину с возвратами более кратким и естественным способом, чем в предыдущих разделах. Применение унификации в процессе поиска в пространстве состояний расширяет возможности рекурсивного поиска.
Рекурсия
В математике рекурсивное определение объекта — это его описание в терминах частей этого же определения. В информатике рекурсия используется для определения и анализа структур данных и процедур. Рекурсивная процедура состоит из следующих этапов.
Рекурсивный шаг: вызов процедуры из этой же процедуры для повторения последовательности действий.
Условие, которое обеспечивает выход из процедуры и таким образом предотвращает зацикливание (рекурсивная версия бесконечного цикла).
Оба этих компонента необходимы и появляются во всех рекурсивных определениях и алгоритмах. Рекурсия — естественный инструмент управления массивами данных, которые имеют правильную структуру и неопределенный размер, например, списками, деревьями и графами. Рекурсия особенно удобна для поиска в пространстве состояний.
Простой пример — алгоритм определения принадлежности данного элемента списку. Списком (list) называют упорядоченную последовательность элементов и фундаментальных строительных блоков структур данных. Списки использовались, например, для представления списков open и closed в алгоритмах поиска. Процедура проверки принадлежности элемента списку определяется так.
function member(item, list); begin
if список пуст then return FAIL 'останов
else if item = первому элементу списка then return SUCCESS
'останов
else
begin
tail := список после удаления первого элемента; member(item,tail) 'рекурсия
end
end.
Эта процедура сначала проверяет, пуст ли список, и, если да, алгоритм возвращает ошибку. В противном случае он сравнивает выбранный элемент с первым элементом списка. Если они равны, происходит успешное завершение процедуры. Таким образом, это условия завершения процедуры. Если ни одно из приведенных выше условий завершения не выполнено, процедура удаляет первый элемент из списка и снова вызывает сама себя для сокращенного списка. Это позволяет исследовать каждый элемент списка по очереди. Обратите внимание на то, что список конечен, и каждый шаг рекурсии уменьшает его размер на один элемент. Это означает, что данный алгоритм не приведет к зацикливанию.
В приведенном выше алгоритме используются две фундаментальные операции со списком: первая из них (head) возвращает первый элемент списка, вторая операция (tail) возвращает список, полученный после удаления первого элемента. Эти операции наряду с рекурсией составляют основу высокоуровневых операций со списком типа member. Данные операции поддерживаются языками обработки списков (например, LISP). Рекурсия, поддерживаемая каким-либо языком программирования, расширяет возможности более традиционных управляющих конструкций, например, циклов и условных операций. Другими словами, любая итерационная процедура может быть также реализована рекурсивно. Удобство рекурсивных формулировок—ясность и компактность выражения. Математические понятия логики или функций не поддерживают таких механизмов, как упорядочение, ветвление и итерация. Для индикации повторения можно использовать рекурсию. Поскольку рекурсию проще описать математически, чем явные итерации, то легче формально проанализировать правильность и сложность рекурсивных алгоритмов. Рекурсия часто используется в системах автоматической генерации или верификации программ, необходимых при создании компиляторов и интерпретаторов. Однако более важным является тот факт, что рекурсия — это естественный способ реализации таких стратегий искусственного интеллекта, как поиск на графе.
Рекурсивный поиск
Прямое преобразование описанного ранее алгоритма поиска в глубину в рекурсивную форму иллюстрирует эквивалентность рекурсии и итерационного подхода. Этот алгоритм для поддержки списка состояний использует глобальные переменные open и closed.
function DepthSearch; ’переменные open и closed глобальные
begin
if список open пуст then return FAIL;
CurrentState := первый элемент списка open;
if CurrentState равно целевому состоянию then return SUCCESS
else
begin
open := хвост списка open;
closed := closed с добавлением CurrentState;
для каждого потомка CurrentState
if не в списке closed или open ’построение стека
then добавить потомок в начало списка open
end;
DepthSearch ’рекурсивный вызов
end.
Поиск в ширину можно описать фактически тем же самым алгоритмом. При этом необходимо сохранять список closed как глобальную структуру данных и рассматривать список open как очередь, а не как стек.
Из представленного алгоритма ясно, что поиск в глубину не использует все возможности рекурсии. Процедуру можно упростить, используя рекурсию непосредственно (а не через список open) для рассмотрения состояний и нахождения путей в их пространстве. В новой версии алгоритма глобальная переменная closed используется для обнаружения повторяющихся состояний и предотвращения циклов. Список open неявно используется в записях активации рекурсивной среды.
Вместо того чтобы находить все потомки данного состояния, а затем помещать их в список open, алгоритм DepthSearch2 рассматривает потомки по одному. Для каждого из них рекурсивно находятся все потомки, а затем рассматривается очередной потомок исходного состояния. Следует заметить, что алгоритм предполагает определенный порядок операторов генерации состояний. Если при рекурсивном поиске некоторый потомок является целевым состоянием, то процедура поиска успешно завершается, и, естественно, алгоритм игнорирует братьев данного потомка. Если рекурсивный вызов для одного из потомков приведет в тупик, то будет рассмотрен брат этого потомка, а также все его потомки. Таким образом, алгоритм обходит весь граф аналогично алгоритму поиска в глубину.
Рекурсия позволяет обойтись без списка open. Механизм, посредством которого можно реализовать рекурсию на каком-либо языке программирования, должен включать отдельную запись активации (activation record) для каждого рекурсивного вызова. Каждая такая запись активации должна содержать локальные переменные и состояние выполнения для каждого вызова процедуры. При каждом рекурсивном вызове процедуры с новым состоянием новая запись активации сохраняет параметры процедуры (состояние), все локальные переменные и текущее состояние выполнения. В рекурсивном алгоритме поиска состояния, находящиеся на рассматриваемом пути, сохраняются в последовательности записей активации рекурсивных вызовов. Запись каждого вызова содержит также последнюю операцию, которая была сделана при генерации соответствующего потомка. Это позволяет генерировать при необходимости брата данного потомка.
function DepthSearch2(CurrentState);
’closed - глобальная переменная
begin
if CurrentState равно целевому состоянию then return SUCCESS; добавить CurrentState в список closed; while CurrentState имеет непроверенные потомки do begin
child := следующий непроверенный потомок; if потомок не член списка closed then
if depthsearch(child) = SUCCESS then return SUCCESS
end;
return FAIL ’поиск исчерпан
end.
Возврат производится, если ни один из потомков данного состояния не привел к цели, что послужило причиной неудачного завершения процедуры. В этом случае в процедуру генерации потомков возвращается значение FAIL. Затем эта процедура применяется к брату данного состояния. В рассматриваемом случае внутренние механизмы рекурсии заменяют список open, который был использован в итерационной версии алгоритма. Рекурсивная реализация позволяет программисту ограничить рассмотрение единственным состоянием и его потомками, а не иметь дело со всем списком open. Возможность рекурсии выражать глобальные понятия в простой форме — главный источник ее удобства.
Поиск в пространстве состояний — процесс рекурсивный по природе. Чтобы найти путь от текущего состояния к цели, необходимо двигаться в дочернее состояние, затем из него перейти к потомку и так далее. Если соответствующее дочернее состояние не ведет к цели, то необходимо рассмотреть состояние того же уровня, на котором находится родительское состояние. Рекурсия разбивает большую и трудную проблему (поиск во всем пространстве состояний) на более простые части (генерирование потомков отдельного состояния), а затем применяет (рекурсивно) эту стратегию к каждому потомку. Этот процесс продолжается до тех пор пока не будет найдено целевое состояние или исчерпано все пространство состояний.
