
- •1 Основные понятия
- •1.1 Происхождение и понимание термина «искусственный интеллект»
- •1.2 Подходы к пониманию проблемы
- •Тест Тьюринга и интуитивный подход
- •Символьный подход
- •Логический подход
- •Агентно-ориентированный подход
- •Гибридный подход
- •1.3 Модели и методы исследований Символьное моделирование мыслительных процессов
- •Работа с естественными языками
- •Представление и использование знаний
- •Машинное обучение
- •Биологическое моделирование искусственного интеллекта
- •Робототехника
- •Машинное творчество
- •Другие области исследований
- •Современный искусственный интеллект
- •Некоторые из самых известных ии-систем:
- •1.4. Классификация интеллектуальных систем
- •1.5 Методы поиска решений
- •Генетические алгоритмы
- •2. Представление знаний в системах искусственного интеллекта
- •2.1 Представление знаний
- •Формальная (Аристотелева) логика и логика высказываний
- •Как упростить логическую формулу?
- •Как решать логические задачи?
- •Решение логических задач средствами алгебры логики
- •Решение логических задач табличным способом
- •Решение логических задач с помощью рассуждений
- •Логика предикатов
- •3 Логическое программирование на прологе
- •Объекты данных
- •Представление списков
- •Некоторые операции над списками
- •Ограничение перебора
- •Пример Пролог программы
- •4 Логика предикатов второго порядка
- •5. Нечеткая логика
- •Нечеткие множества
- •Основные характеристики нечетких множеств
- •Методы построения функций принадлежности нечетких множеств
- •Операции над нечеткими множествами
- •Наглядное представление операций над нечеткими множествами
- •Свойства операций и
- •Нечеткая и лингвистическая переменные
- •Нечеткие высказывания и нечеткие модели систем
- •Нечеткая база знаний
- •6 Байесовы сети
- •6.1. Простейший логический вывод
- •6.2. Распространение вероятностей в эс
- •6.3. Последовательное распространение вероятностей
- •6.4. Экспертные системы, использующие субъективные вероятности
- •6.5 Байесовские сети доверия как средство разработки эс
- •6.5.1. Основные понятия и определения
- •6.5.2. Пример построения простейшей байесовской сети доверия
- •6.5.3. Процесс рассуждения (вывода) в байесовских сетях доверия
- •6.5.4. Байесовские сети доверия как одно из направлений современных экспертных систем
- •6.6 Сети доверия с условными гауссовскими переменными
- •6.6.1. Непрерывные случайные величины
- •6.6.2. Непрерывные гауссовские переменные
- •6.6.3. Числовые характеристики случайных величин
- •6.6.4. Совместное использование дискретных и непрерывных переменных в байесовских сетях доверия
- •6.6.5. Логический вывод в байесовских сетях доверия с непрерывными и дискретными состояниями
- •6.7 Экспертные системы на основе теории Демстера-Шеффера
- •6.7.1. Предпосылки возникновения новой теории.
- •6.7.2. Основы теории Демстера-Шеффера
- •6.7.3. Меры доверия и правдоподобия в тдш
- •6.7.4. Отличие тдш от теории вероятностей
- •6.7.5. Связь между тдш и классической теорией вероятностей
- •6.7.6. Комбинация функций доверия
- •7 Решатели проблем, основанных на знаниях
- •7.1 Семантические сети
- •7.2 Фреймы
- •7.3 Нейронные сети
- •7.4 Экспертные системы
- •Модель экспертных систем
- •7 Распознание образов Контурный анализ
- •Код Фримена
- •Современные программные и инструментальные средства создания искусственного интеллекта
1.5 Методы поиска решений
Поиск в пространстве состояний (англ. state space search) — группа методов, предназначенных для решения задач искусственного интеллекта. Методы поиска в пространстве состояний осуществляют последовательный просмотр конфигураций или состояний задачи с целью обнаружения целевого состояния, имеющего заданные характеристики. В основном в данных методах используется поиск с использованием графов
Большинство алгоритмических формулировок поиска на графах использует понятие явного графа (англ. explicit graph). Граф может быть представлен в виде матрицы смежности или списка смежности.
В алгоритмах поиска в пространстве состояний применяется понятие неявного графа (англ. implicit graph). Отличие состоит в том, что рёбра графа не хранятся в памяти явно, а порождаются «на лету» (англ. on-the-fly) набором правил перехода. Определение графа пространства состояний включает в себя начальную вершину, множество целевых вершин и процедуру развёртывания вершины
Методы поиска в пространстве состояний делятся на информированные и неинформированные.
Неинформированные методы (методы слепого поиска, методы грубой силы) не используют никакой информации о конкретной задаче. Они последовательно просматривают все состояния до тех пор, пока не будет найдено решение. Различия между методами неинформированного поиска сводятся к порядку просмотра состояний.
Информированные методы поиска (эвристические методы) пользуются дополнительной информацией о конкретной задаче. Дополнительная информация (эвристика) позволяет сократить перебор путём исключения заведомо бесперспективных вариантов. Такой подход ускоряет работу алгоритма по сравнению с полным перебором. Платой за это является отсутствие гарантии того, что выбрано правильное или наилучшее из всех возможных решение.
Поиск в ширину (breadth-first search, BFS) — это стратегия поиска решений в пространстве состояний, в которой вначале развёртывается корневой узел, затем — все преемники корневого узла, после этого развёртываются преемники этих преемников и т.д. Прежде чем происходит развёртывание каких-либо узлов на следующем уровне, развёртываются все узлы на данной глубине в дереве поиска.
Алгоритм является полным. Если все действия имеют одинаковую стоимость, поиск в ширину является оптимальным.
Реализация поиска в ширину может использовать очередь FIFO. В начале очередь содержит только корневой узел. На каждой итерации основного цикла, из начала очереди извлекается узел curr. Если узел curr является целевым, поиск останавливается, в противном случае узел curr развёртывается, и все его преемники добавляются в конец очереди.
function BFS(v : Node) : Boolean;
begin
enqueue(v);
while queue is not empty do
begin
curr := dequeue();
if is_goal(curr) then
begin
BFS := true;
exit;
end;
mark(curr);
for next in successors(curr) do
if not marked(next) then
begin
enqueue(next);
end;
end;
BFS := false;
end;
Поиск по критерию стоимости
Поиск по критерию стоимости (метод равных цен, uniform-cost search, UCS) — обобщение алгоритма поиска в ширину, учитывающее стоимости действий (рёбер графа состояний). Поиск по критерию стоимости развёртывает узлы в порядке возрастания стоимости кратчайшего пути от корневого узла. На каждом шаге алгоритма развёртывается узел с наименьшей стоимостью g(n). Узлы хранятся в очереди с приоритетом.
Этот алгоритм является полным и оптимальным, если стоимости этапов строго положительны. Если стоимости всех этапов равны, поиск по критерию стоимости идентичен поиску в ширину.
Процедура поиска по критерию стоимости может войти в бесконечный цикл, если окажется, что в ней развёрнут узел, имеющий действие с нулевой стоимостью, которое снова указыает на то же состояние. Можно гарантировать полноту и оптимальность поиска при условии, что стоимости всех действий строго положительны.
Поиск по критерию стоимости логически эквивалентен алгоритму Дейкстры . В частности, оба алгоритма развёртывают одни и те же узлы в одном и том же порядке. Основное различие связано с наличием узлов в очереди с приоритетом: в алгоритме Дейкстры все узлы добавляются в очередь при инициализации, а в алгоритме поиска по критерию стоимости узлы добавляются «на лету» (англ. on-the-fly, lazily) во время поиска. Из этого следует, что алгоритм Дейкстры применим к явно заданным графам, в то время как алгоритм UCS может быть применён как к явным, так и к неявным графам.
Поиск в глубину
Поиск в глубину (depth-first search, DFS) — стратегия поиска решений в пространстве состояний, при которой всегда развёртывается самый глубокий узел в текущей периферии дерева поиска. При поиске в глубину анализируется первый по списку преемник текущего узла, затем — его первый преемник и т. д. Развёрнутые узлы удаляются из периферии, поэтому в дальнейшем поиск «возобновляется» со следующего самого поверхностного узла, который всё ещё имеет неисследованных преемников.
Стратегия поиска в глубину может быть реализована с помощью стека LIFO или с помощью рекурсивной функции
function DFS(v : Node; depth : Integer) : Boolean;
begin
if is_goal(v) then
begin
DFS := true;
exit;
end;
for next in successors(v) do
if DFS(next, depth + 1) then
begin
DFS := true;
exit;
end;
DFS := false;
end;
Поиск с ограничением глубины (depth-limited search, DLS) — вариант поиска в глубину, в котором применяется заранее определённый предел глубины l, что позволяет решить проблему бесконечного пути.
Поиск с ограничением глубины не является полным, так как при l < d цель не будет найдена, и не является оптимальным при l > d.
Поиск с ограничением глубины применяется в алгоритме поиска с итеративным углублением.
function DLS(v : Node; depth, limit : Integer) : Boolean;
begin
if (depth < limit) then
begin
if is_goal(v) then
begin
DLS := true;
exit;
end;
for next in successors(v) do
begin
if DLS(next, depth + 1, limit) then
begin
DLS := true;
exit;
end;
end;
end;
DLS := false;
end;
Поиск в глубину с итеративным углублением (iterative-deepening depth-first search, IDDFS, DFID) — стратегия, которая позволяет найти наилучший предел глубины поиска DLS. Это достигается путём пошагового увеличения предела l до тех пор, пока не будет найдена цель.
function IDDFS(v : Node) : Integer;
var
lim: Integer;
begin
lim := 0;
while not DLS(v, 0, lim) do
lim := lim + 1;
IDDFS := lim;
end;
Двунаправленный поиск (bidirectional search) в ширину (или глубину) — усложнённый алгоритм поиска в ширину (или глубину), идея которого заключается в том, что можно одновременно проводить два поиска (в прямом направлении, от начального состояния, и в обратном направлении, от цели), останавливаясь после того, как два процесса поиска встретятся на середине.
Двунаправленный поиск может быть основан на стратегии итеративного углубления. Одна итерация включает в себя поиск на глубину k в прямом направлении и два поиска на глубину k и k + 1 в обратном направлении.
Поиск A* (произносится «А звезда») — в информатике и математике, алгоритм поиска по первому наилучшему совпадению на графе, который находит маршрут с наименьшей стоимостью от одной вершины (начальной) к другой (целевой, конечной).
Порядок обхода вершин определяется эвристической функцией «расстояние + стоимость» (обычно обозначаемой как f(x)). Эта функция — сумма двух других: функции стоимости достижения рассматриваемой вершины (x) из начальной (обычно обозначается как g(x) и может быть как эвристической, так и нет) и эвристической оценкой расстояния от рассматриваемой вершины к конечной (обозначается как h(x)).
Функция h(x) должна быть допустимой эвристической оценкой, то есть не должна переоценивать расстояния к целевой вершине. Например, для задачи маршрутизации h(x) может представлять собой расстояние до цели по прямой линии, так как это физически наименьшее возможное расстояние между двумя точками
A* пошагово просматривает все пути, ведущие от начальной вершины в конечную, пока не найдёт минимальный. Как и всеинформированные алгоритмы поиска, он просматривает сначала те маршруты, которые «кажутся» ведущими к цели. Отжадного алгоритма (который тоже является алгоритмом поиска по первому лучшему совпадению) его отличает то, что при выборе вершины он учитывает, помимо прочего, весь пройденный до неё путь (составляющая g(x) — это стоимость пути от начальной вершины, а не от предыдущей, как в жадном алгоритме). В начале работы просматриваются узлы, смежные с начальным; выбирается тот из них, который имеет минимальное значение f(x), после чего этот узел раскрывается. На каждом этапе алгоритм оперирует с множеством путей из начальной точки до всех ещё не раскрытых (листовых) вершин графа («множеством частных решений»), которое размещается в очереди с приоритетом. Приоритет пути определяется по значению f(x) = g(x) + h(x). Алгоритм продолжает свою работу до тех пор, пока значение f(x) целевой вершины не окажется меньшим, чем любое значение в очереди (либо пока всё дерево не будет просмотрено). Из множественных решений выбирается решение с наименьшей стоимостью.
Чем меньше эвристика h(x), тем больше приоритет (поэтому для реализации очереди можно использовать сортирующие деревья).
Псевдокод:
function A*(start,goal)
% множество уже пройденных вершин
var closed := the empty set
% множество частных решений
var q := make_queue(path(start))
while q is not empty
var p := remove_first(q)
var x := the last node of p
if x in closed
continue
if x = goal
return p
add x to closed
% добавляем смежные вершины
foreach y in successors(x)
enqueue(q, p, y)
return failure
Псевдокод с подробными комментариями:
function A*(start,goal)
closedset := the empty set // Множество вершин, которые уже были обработаны(раскрыты)
openset := {start} // Множество вершин(очередь), которые предстоит обработать(раскрыть).
// Изначально здесь присутствует только начальная вершина start.
path_map := the empty set // Карта пройденных вершин. Используется функцией reconstruct_path
//Заполняем свойства вершины start
start.g := 0 // g(x). Стоимость пути от начальной вершины. У start g(x) = 0
start.h := heuristic_cost_estimate(start, goal) // Эвристическая оценка расстояние до цели. h(x)
start.f := start.g + start.h // f(x) = g(x) + h(x)
while openset is not empty
x := вершина из openset имеющая самую низкую оценку f(x)
if x = goal
return reconstruct_path(start,goal) //заполняем карту path_map
remove x from openset // Вершина x пошла на обработку, а значит её следует удалить из очереди на обработку
add x to closedset // И добавить в список уже обработанных
foreach y in neighbor_nodes(x) // Проверяем каждого соседа x
if y in closedset // Пропускаем соседей из закрытого списка
continue
tentative_g_score := x.g + dist_between(x,y) // Вычисляем g(x) для обрабатываемого соседа
if y not in openset // Если сосед x ещё не в открытом списке - добавим его туда
add y to openset
tentative_is_better := true
else // Сосед был в открытом списке, а значит мы уже знаем его g(x), h(x) и f(x)
if tentative_g_score < y.g
// Вычисленная g(x) оказалась меньше, а значит нужно будет обновить g(x), h(x), f(x)
tentative_is_better := true
else
// Вычисленная g(x) оказалась больше, чем имеющаяся в openset.
// Это означает, что из вершины x путь через этого соседа дороже
// т.е. существует менее дорогой маршрут, пролегающий через этого соседа (из какой-то другой вершины, не из x)
// Поэтому данного соседа мы игнорируем
tentative_is_better := false
// Обновление свойств соседа.
if tentative_is_better = true
y.came_from := x //Вершина с которой мы пришли. Используется для реконструкции пути.
y.g := tentative_g_score
y.h := heuristic_cost_estimate(y, goal)
y.f := g_score[y] + h_score[y]
// Обратите внимание, что если происходит обновление свойств - значит y(сосед x)
// так или иначе находится в openset.
// Т.е. при следующей итерации внешнего цикла из openset будет извлечена вершина с наименьшей оценкой f(x)
// Не исключено, что она окажется соседом нашего x, которого мы только что добавили.
// В общем это самая важная особенность алгоритма А*
return failure //управление передаётся сюда когда openset пуст, а goal не найден (путь найти не удалось)
// Заполняет карту path_map
// Путь можно проследить только от заданной вершины(чаще всего это goal)
// к старту(каждая вершина имеет свойство came_from, чем мы и воспользуемся)
function reconstruct_path(start_node, goal_node)
// Добавляем в карту все вершины от finish_node до start_node.
current_node := goal_node // поиск начинается от финиша
while current_node <> NULL
path_map.add_node(current_node) // Добавить вершину в карту
current_node := current_node.came_from
return path_map