Sb99055
.pdfЗдесь tj и Lj описывают элементы агрегатора: tj – терм, Lj – литерал. Если литерал пустой, а терм не пустой, то двоеточие не используется. Func – имя функции, которая будет применена к термам. Функция может отсутствовать. Ограничения «s1 <1» и «<2 s2» могут отсутствовать. При этом «<1» и «<2» по умолчанию означают «<=». Значения «s1» и «s2» определяют нижнюю и верхнюю границы.
Поддерживаемые функции: #count (количество атомов в группе), #sum (сумма значений всех термов), #sum+ (сумма всех положительных значений термов-весов), #min (минимальное значение термов-весов), #max (максимальное значение термов-весов).
В результате использования агрегатора формируется набор ответов, соответствующий заданным условиям:
10 #sum{8: course(db); 4: course(web); 6:
course(ai)}.
Результаты:
Answer: 1 course(db) course(web)
Answer: 2 course(ai) course(web) course(db) Answer: 3 course(ai) course(db)
Answer: 4 course(ai) course(web)
Вычисление сумм при этом происходит при использовании следующих значений: 10 <= #sum{8; 4; 6}. Во всех случаях сумма весов получалась больше либо равна 10. Исключим равенство суммы термов-весов 10.
10 < #sum{8: course(db); 4: course(web); 6:
course(ai)}.
При этом в наборе ответов встретятся только первые три ответа. Рассмотрим пример для #count:
2 #count{1: course(db); 2: course(web); 3:
course(ai)} 2.
Результаты:
Answer: 1 course(web) course(db)
Answer: 2 course(ai) course(web)
Answer: 3 course(ai) course(db)
Вприведённом примере количество атомов в ответе должно быть равно
2.То же самое можно записать следующим образом:
#count{1: course(db); 2: course(web); 3: course(ai)}
= 2.
11
Вычисление при этом представляет собой определение количества
#count{1; 2; 3} = 2.
Рассмотренные варианты агрегаторов могут использоваться как в голове, так и в теле правил:
a.
cnt(X) :- X = #count{ -2 : a; 3 : a }. sum(X) :- X = #sum { -2 : a; 3 : a }. pos(X) :- X = #sum+{ -2 : a; 3 : a }. min(X) :- X = #min { -2 : a; 3 : a }.
max(X) :- X = #max { -2 : a; 3 : a }.
Результат наглядно демонстрирует применение функций:
Answer: 1 a cnt(2) sum(1) pos(3) min(-2) max(3)
Рассмотрим программу с суммированием:
#sum{ 3 : cost(1,2,3); 3 : cost(2,3,3) } = 3.
Её результаты:
Answer: 1 cost(1,2,3)
Answer: 2 cost(2,3,3)
Answer: 3 cost(2,3,3) cost(1,2,3)
Следует отметить, что использованы одинаковые термы-веса, в то же время ASP ожидает, что они будут уникальны, именно поэтому в результате появился ответ № 3. Эту программу можно изменить следующим образом.
#sum{ 3,a : cost(1,2,3); 3,b : cost(2,3,3) } = 3.
Тогда результат будет следующий:
Answer: 1 cost(1,2,3)
Answer: 2 cost(2,3,3)
В данном случае получились уникальные термы 3,a и 3,b, а суммирование выполняется только по первым числам.
Использование сокращений
Если необходимо задать ограничение на количество результирующих атомов, допустима запись, в которой опущено указание на функцию #count и не приводятся термы-веса:
{course(db); course(web); course(ai)} = 2.
Результат:
Answer: 1 course(web) course(db)
Answer: 2 course(ai) course(web)
12
Answer: 3 course(ai) course(db)
Атомы, сгенерированные агрегаторами, могут отфильтровываться с помощью ограничений целостности:
{course(db); course(web); course(ai)} = 2.
:- course(web).
Результат:
Answer: 1 course(db) course(ai)
Рассмотрим программу «сваха»:
male(tom;alex). female(mary;liza). {couple(X, Y)} :- male(X), female(Y). :- couple(X, Y), couple(X, Z), Y != Z.
:- couple(X, Y), couple(Z, Y), X != Z.
В предложенной программе первая строка задаёт перечень представителей мужского и женского пола. Вторая строка с использованием агрегатора описывает все возможные супружеские пары. Ограничения целостности в третьей и четвёртой строке – запрещают многоженство и многомужество. Результаты:
Answer: 1 ...
Answer: 2 ... couple(alex,mary)
Answer: 3 ... couple(tom,liza)
Answer: 4 ... couple(alex,mary) couple(tom,liza) Answer: 5 ... couple(alex,liza)
Answer: 6 ... couple(tom,mary)
Answer: 7 ... couple(tom,mary) couple(alex,liza)
Приведённый пример демонстрирует следующие особенности использования механизма агрегаторов в ASP.
1.Использование агрегаторов в голове правила. При этом генерируются значения, но нет возможности задать нижнюю и верхнюю границы или использовать функции.
2.Создание с использованием агрегатора новых фактов в программе.
3.Исключение с использованием ограничений целостности результатов, созданных агрегатором, но не удовлетворяющим данному ограничению.
1.7. Оптимизация
Использование оптимизации позволяет не просто найти набор ответов, а найти оптимальный набор ответов. Предусмотрена линейная оптимизация с
13
получением минимальных (#minimize) и максимальных (#maximize) значений оптимизируемого параметра:
#minimize{w1@p1,t1 : L1, ... , wn@pn,tn : Ln}
В данном описании @pj – приоритет (необязательное значение), wj – вес, который будет минимизироваться среди истинных литералов Lj
(1 ≤ j ≤ n).
Оптимизацию называют мягким ограничением. Для решения задачи минимизации существует альтернативная запись.
: ~noisy. [ 1@3 ]
#minimize { 1@3 : noisy }.
Приведённые две записи с точки зрения ASP полностью идентичны. Рассмотрим следующую программу.
{ hotel(1..5) } = 1. star(1,5). cost(1,170). star(2,4). cost(2,140). star(3,3). cost(3,90).
star(4,3). cost(4,75). main_street(4). star(5,2). cost(5,60).
noisy :- hotel(X), main_street(X). #maximize{Y@1,X : hotel(X), star(X,Y)}.
#minimize{Y/Z@2,X : hotel(X), cost(X,Y), star(X,Z)}.
#minimize{1@3 : noisy}.
Дано пять отелей, определена их «звёздность», стоимость и шумность. Последнее ограничение говорит, что не нужен шумный отель. В первую очередь требуется максимизировать звёздность, во вторую – минимизировать отношение стоимости на звездность. Из программы видно, что под требование минимизации подходят два отеля № 3 и № 5, но у отеля № 3 выше «звёздность». Результат:
Answer: 1 ... hotel(1)
Optimization: 0 34 12
Answer: 2 ... hotel(3)
Optimization: 0 30 14
OPTIMUM FOUND
14
1.8. Дополнительные возможности ASP
Комментарии начинаются с символа «%», для многострочных комментариев используется символ открытия «%*» и символ закрытия «*%» комментариев.
Директива #show ограничивает результаты вывода. Для примера с отелями (раздел 1.7):
#show hotel/1.
При использовании данной директивы в качестве результата будут вы-
ведены только hotel(1) и hotel(3).
Директива #const позволяет задавать константы, которые могут изменяться в командной строке:
#const x = 42.
#const y = f(x,z).
p(x,y).
Результат:
p(42,f(42,z))
Замена константы:
clingo.exe --text -c x="2+2*2" -c z=7 1.lp
Результат:
p(6,f(6,7)).
Рассмотрим вычисление чисел Фибоначчи: x(n) = x(n-1) + x(n-2).
#const n=4. num(1..n).
fib(0, 1). fib(1, 1).
fib(N, X1 + X2) :- num(N), N > 1, fib(N - 1, X1), fib(N - 2, X2).
#show fib/2.
Результат:
fib(0,1) fib(1,1) fib(2,2) fib(3,3) fib(4,5)
1.9.Упражнения
1.Задан набор фактов, описывающих числа:
#const n = 5.
4{num(1..n)}.
15
Дополните программу таким образом, чтобы был только один набор ответов, в котором игнорируется число 2. Единственный набор ответов для n=5:
num(1) num(3) num(4) num(5)
2. Задан набор фактов, описывающих генеалогическое дерево:
person(tom; bob; alex; liza; sam; mary; lucy).
parent(tom,(bob;alex)). parent(bob,(liza;sam)).
parent(sam,(mary;lucy)).
male(tom;bob;alex;sam).
female(liza;mary;lucy).
Напишите программу «есть сестра», которая отобразит только тех, у кого есть сестра. Правильный ответ для приведённой программы:
havesister(sam) havesister(lucy) havesister(mary)
3. Для набора фактов, описывающих генеалогическое дерево из упражнения (2):
Напишите программу «есть тетя», которая отобразит только тех, у кого есть тетя. Правильный ответ для программы из упражнения (2):
haveaunt(mary) haveaunt(lucy)
4. Дан набор фактов для вычисления факториала: x(n) = x(n-1) * n.
#const n=5.
num(1..n). fact(1, 1).
#show fact/2.
Необходимо дополнить программу, чтобы она вычисляла факториал. Единственный набор ответов для n=5:
fact(1,1) fact(2,2) fact(3,6) fact(4,24) fact(5,120)
5. Дан набор фактов, описывающих числа:
#const n = 12.
num(2..n).
#show prime/1.
Необходимо дополнить программу, чтобы в наборе ответов были только простые числа, меньшие n. Единственный набор ответов для n=12:
prime(2) prime(3) prime(5) prime(7) prime(11)
6. Дан набор фактов, описывающих числа:
#const n = 30.
num(2..n).
16
#show prime6/2.
Необходимо дополнить программу, чтобы в наборе ответов были только пары простых чисел X и Y, меньшие n, отличающиеся на 6. Единственный набор ответов для n=30:
prime6(5,11) prime6(7,13) prime6(11,17)
prime6(13,19) prime6(17,23) prime6(23,29)
7. Задан набор фактов, описывающих решетку 5 на 5:
#const n = 5.
1 { grid(1..n, 1..n) } n*n.
Напишите программу, которая сформирует маршрут из позиции grid(1,1) в grid(5,5). Пример правильного ответа:
move(1,1) move(2,1) move(3,1) move(4,1) move(4,2)
move(4,3) move(4,4) move(4,5) move(5,5)
Для упрощения решения можете исключить из ответа move(1,1) и/или move(5,5).
2.Подходы к решению задач
2.1.Задача о расстановке ферзей
Шахматная фигура ферзь бьёт по горизонтали, по вертикали и по обеим диагоналям. В классической постановке задачи о расстановке ферзей необходимо на доске 8×8 расставить 8 ферзей так, чтобы они не били друг друга. Эта задача может решаться для доски размера n×n.
#const n = 8.
{ queen(1..n,1..n) }. :- { queen(I,J) } != n.
:- queen(I,J), queen(I,X), J != X. :- queen(I,J), queen(X,J), I != X.
:- queen(I,J), queen(X,Y), (I,J) != (X,Y), I-J == X-
Y.
:- queen(I,J), queen(X,Y), (I,J) != (X,Y), I+J == X+Y.
В программе строка 1 – размер доски 8×8. Строка 2 – все возможные варианты расстановки ферзей. Строка 3 – количество ответов равно 8. Строки 4
и5 – запрет нахождения ферзей на одной вертикали и горизонтали. Строки 6
и7 – запрет нахождения на одной диагонали.
17
В результате получается 92 набора ответов следующего вида:
queen(5,1) queen(2,2) queen(4,3) queen(6,4) queen(8,5) queen(3,6) queen(1,7) queen(7,8)
queen(5,1) queen(7,2) queen(4,3) queen(1,4)
queen(3,5) queen(8,6) queen(6,7) queen(2,8)
Возможен другой вариант решения задачи о расстановке ферзей:
#const n = 8. number(1..n).
1 { queen(X,Y) : number(Y) } 1 :- number(X). { queen(1..n,Y) } = 1 :- Y = 1..n.
:- queen(I,J), queen(X,Y), I < X, J+I == Y+X. :- queen(I,J), queen(X,Y), I < X, J-I == Y-X. #show queen/2.
Впрограмме строка 1 – размер доски 8×8. Строка 2 – определение набора чисел от 1 до n. Строки 3 и 4 идентичны друг другу и задают все варианты размещения ферзей на шахматной доске. Строки 5 и 6 обеспечивают запрет нахождения ферзей на одной диагонали, вертикали или горизонтали.
Врезультате получаем 92 ответа следующего вида:
queen(1,4) queen(2,6) queen(3,8) queen(4,2)
queen(5,7) queen(6,1) queen(7,3) queen(8,5)
Программа может быть сокращена. Альтернативный вариант решения:
#const n = 8.
{queen(I,1..n) } = 1 :- I = 1..n.
{queen(1..n,J) } = 1 :- J = 1..n.
:- { queen(D-X,X) } > 1, D = 2..2*n.
:- { queen(D+Y,Y) } > 1, D = 1-n..n-1.
В результате получаем 92 ответа следующего вида:
queen(2,2) queen(5,1) queen(4,3) queen(1,7)
queen(3,6) queen(6,4) queen(8,5) queen(7,8)
2.2.Задача коммивояжера
Взадаче коммивояжера дан направленный взвешенный граф, и необходимо найти маршрут через все вершины с минимальным весом.
%* Дан взвешенный граф (cost). Первый параметр – начальная вершина дуги, второй параметр – конечная вершина дуги, третий параметр – вес. *%
18
cost(1,2,2). cost(1,3,3). cost(1,4,1).
cost(2,4,2). cost(2,5,2). cost(2,6,4).
cost(3,1,3). cost(3,4,2). cost(3,5,2).
cost(4,1,1). cost(4,2,2).
cost(5,3,2). cost(5,4,2). cost(5,6,1).
cost(6,2,4). cost(6,3,3). cost(6,5,1).
% Дуга описывается edge (см. параметры cost)
edge(X,Y) :- cost(X,Y,_).
% Узел node – первый либо второй параметр cost
node(X) :- cost(X,_,_). node(Y) :- cost(_,Y,_). % Поиск циклов
{cycle(X,Y) : edge(X,Y) } = 1 :- node(X).
{cycle(X,Y) : edge(X,Y) } = 1 :- node(Y).
%* Должен быть ровно один цикл по всем вершинам. Без ограничения целостности может получиться не-
сколько циклов. *%
reached(Y) :- cycle(1,Y).
reached(Y) :- cycle(X,Y), reached(X).
:- node(Y), not reached(Y). % Поиск минимального решения
#minimize { C,X,Y : cycle(X,Y), cost(X,Y,C) }.
#show cycle/2.
В результате находится один набор ответов, обеспечивающий вес пути, равный 11.
Answer: 1 cycle(1,4) cycle(4,2) cycle(3,1) cycle(2,6) cycle(6,5) cycle(5,3)
Optimization: 13
Answer: 2 cycle(1,4) cycle(4,2) cycle(3,1) cycle(2,5) cycle(6,3) cycle(5,6)
Optimization: 12
Answer: 3 cycle(1,2) cycle(4,1) cycle(3,4) cycle(2,5) cycle(6,3) cycle(5,6)
Optimization: 11
OPTIMUM FOUND
19
2.3.Задача о раскрашивании графа
Взадаче о раскрашивании графа предлагается назначить цвета узлам графа таким образом, чтобы смежные вершины имели разные цвета. Возможны два варианта решения задачи: для направленного графа и для ненаправленного графа. Рассмотрим решение задачи для направленного графа.
% Узлы
node(1..6).
%* Направленные дуги edge. Первый параметр – начальный узел, второй параметр – конечный узел *%
edge(1,(2;3;4)). edge(2,(4;5;6)). edge(3,(1;4;5)).
edge(4,(1;2)). edge(5,(3;4;6)). edge(6,(2;3;5)). % Количество цветов, в которые раскрашивается граф
#const n = 3.
%Возможные варианты цветов для каждого узла графа
{color(X,1..n) } = 1 :- node(X).
%Проверка: соседние вершины имеют разные цвета
:- edge(X,Y), color(X,C), color(Y,C).
#show color/2.
В результате получается один набор ответов:
color(2,2) color(1,3) color(3,2) color(4,1)
color(5,3) color(6,1)
Задача ненаправленного графа может быть сформулирована как задача раскрашивания стран на карте в минимальное количество цветов так, чтобы соседние страны имели разные цвета.
% Страны на карте (узлы графа)
countries(belgium;denmark;france;germany;netherlands). % Предполагается использовать 3 цвета
colors(red;green;blue). % Дуги графа
edge(france,(belgium;germany)).
edge(netherlands,belgium).
edge(germany,(belgium;netherlands;denmark)). % Дуги графа должны быть ненаправленные
neighbour(X,Y) :- edge(X,Y).
neighbour(Y,X) :- edge(X,Y).
20