Алгоритмы точного вычисления гиперобъема — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 59: Строка 59:
 
Также, из алгоритма расслоения следует, что из части с <tex>n</tex> точками будет получено по одной части для каждого <tex>i = 1...n</tex>, то есть: <center><tex>f(n, d) = \sum \limits_{i = 1}^{n}f(i, d - 1)</tex>.</center>
 
Также, из алгоритма расслоения следует, что из части с <tex>n</tex> точками будет получено по одной части для каждого <tex>i = 1...n</tex>, то есть: <center><tex>f(n, d) = \sum \limits_{i = 1}^{n}f(i, d - 1)</tex>.</center>
  
 +
1) Покажем, что: <center><tex>{x \choose y} = {x - r \choose y} + \sum \limits_{i = 1}{r} {x - i \choose y - 1}</tex>.</center>
 +
Индукция по <tex>r</tex>. База: <center><tex>{x \choose y} = {x - 1 \choose y} + {x - 1 \choose y - 1}</tex>.</center>
 +
 +
2)
  
  
 
}}
 
}}
 +
 +
Таким образом, на этот алгоритм получена более низкая оценка времени работы, чем на предыдущий, и это подтверждается на практике [1].
 +
 +
== Сведение к задаче KMP (Klee's Measure Problem) ==
 +
 +
Задача KMP состоит в нахождении объема объединения прямоугольных гиперпараллелепипедов в <tex>d</tex>-мерном пространстве. Как показано в описании алгоритма IEA, исходная задача легко сводится к этой, если каждой точке поставить в соответствие гиперкуб с одной вершиной в центре координат, а противоположной - в этой точке.
 +
 +
Существует несколько алгоритмов решения задачи KMP, самый оптимальный из которых использует идеи сканирующей гиперплоскости, [[Статистики на отрезках. Корневая эвристика|корневой эвристики]] и КД-дерево, и позволяет решать задачу за время <tex>O(n^{d/2}\log n)</tex>. Рассмотрим его.
 +
 +
Для начала изложим идею сканирующей гиперплоскости. Рассмотрим всевозможные значения <tex>d</tex>-ой координаты у точек множества <tex>X</tex>.
 +
Возьмем гиперплоскость, перпендикулярную оси <tex>d</tex>-ой координаты, будем ее двигать по этим значениям от минимального до максимального и рассматривать проекцию всех гиперкубов на эту гиперплоскость. Заметим, что между точками проекция меняться не будет, а в каждой точке будут появляться или исчезать проекции некоторых гиперкубов. Поэтому, если уметь эффективно пересчитывать объем проекции при каждом появлении/исчезновении и прибавлять это значение, умноженное на расстояние между последовательными значениями <tex>d</tex>-ой координаты, то можно легко посчитать суммарный гиперобъем. Как раз для эффективного пересчета используется такая структура, как КД-дерево.
 +
 +
Теперь изложим идею алгоритма на примере трехмерного пространства.
 +
Будем считать, что сканирующая плоскость двигается перепендикулярно оси <tex>OZ</tex>. В каждый момент проекция всех параллелепипедов на эту плоскость предствляет собой множество прямоугольников и необходимо уметь обрабатывать следующие три запроса:
 +
# добавить прямоугольник
 +
# удалить прямоугольник
 +
# посчитать площадь объединения всех прямоугольников
 +
 +
{{Определение
 +
|definition=КД-деревом называется [[Дерево поиска, наивная реализация|сбалансированное двоичное дерево]], где каждой вершине <tex>\alpha</tex> соответствует некоторая область <tex>C_{\alpha}</tex> <tex>d</tex>-мерного пространстве, удовлетворяющая следующим свойствам:
 +
# Корневой вершине <tex>root</tex> соответствует <tex>C_{root}</tex> - все пространство.
 +
# Каждое <tex>C_{\alpha}</tex> является гиперпараллелепипедом (возможно бесконечным в некоторых направлениях).
 +
# Для каждой вершины <tex>\alpha</tex> с детьми <tex>\beta</tex> и <tex>\gamma</tex> верно, что области <tex>C_{\beta}</tex> и <tex>C_{\gamma}</tex> не пересекаются и <tex>C_{\alpha} = C_{\beta} \cup C_{\gamma}</tex>.
 +
}}
 +
 +
Будем хранить прямоугольники в КД-дереве следующим образом:
 +
# Для каждого листа <tex>\alpha</tex> будем хранить все прямоугольники, которые пересекают внутреннюю часть области <tex>C_{\alpha}</tex>.
 +
# Для каждой внутренней вершины <tex>\alpha</tex> будем считать число <tex>Cover_{\alpha}</tex> - количество прямоугольников, которые полностью покрывают область <tex>C_{\alpha}</tex>, но не полностью покрывают область родителя этой вершины <tex>C_{father(\alpha)}</tex>.
 +
 +
Также для каждой вершины будем хранить значение площади пересечения области этой вершины со всеми прямоугольниками <tex>M</tex>, которое определяется следующим образом:
 +
# Для каждого листа <tex>M</tex> равно площади пересечения всех прямоугольников с областью этого листа.
 +
# Для каждой внутренней вершины <tex>\alpha</tex> если <tex>Cover_{\alpha} > 0</tex>, тогда <tex>M</tex> равно площади всех области <tex>C_{\alpha}</tex>, иначе <tex>M</tex> равно сумме этих значений для двух сыновей этой вершины.
 +
 +
Таким образом, значение для корневой вершины <tex>M_{root}</tex> и является искомой площадью объединения всех прямоугольников.
 +
 +
Рассмотрим операцию добавления прямоугольника (box) в КД-дерево.
 +
 +
  procedure Insert(box, <tex>\alpha</tex>)
 +
  if <tex>\alpha</tex> - лист then
 +
    добавить box в эту вершину
 +
    пересчитать <tex>M_{\alpha}</tex>
 +
  elseif box покрывает область <tex>C_{\alpha}</tex> then
 +
    <tex>Cover_{\alpha} = Cover_{\alpha} + 1</tex>
 +
    <tex>M_{\alpha} = </tex> объем области <tex>C_{\alpha}</tex>
 +
  elseif box пересекает область <tex>C_{\alpha}</tex> then
 +
    Insert(box, leftson(<tex>\alpha</tex>))
 +
    Insert(box, rightson(<tex>\alpha</tex>))
 +
    if <tex>Cover_{\alpha} > 0 </tex> then
 +
      <tex>M_{\alpha} = </tex> объем области <tex>C_{\alpha}</tex>
 +
    else
 +
      <tex>M_{\alpha} = M_{leftson(\alpha)} + M_{rightson(\alpha)}</tex>
 +
 +
Аналогично устроена операция удаления прямоугольника - она выполняет обратные действия.

Версия 23:35, 17 июня 2012

Эта статья находится в разработке!

Постановка задачи

[math]x = (x_1, x_2, ..., x_d; x_i \ge 0) \in R^d[/math] - точка в [math]d[/math]-мерном пространстве.

Точка [math]x[/math] доминирует точку [math]y[/math] ([math]x \succ y[/math]), если [math]\forall i : x_i \ge y_i, \exists j : x_j \gt y_j[/math].

[math]X = (x^1, x^2, ..., x^n) \subset R^d[/math] - множество из [math]n[/math] точек в [math]d[/math]-мерном пространстве таких, что [math]\nexists i \neq j : x_i \succ x_j[/math] - никакая точка не доминируется другой точкой из этого множества.

[math]S(X) = \mu (\bigcup \limits_{x \in X} \{y | y \succ x\}) [/math] - гиперобъем множества [math]X[/math].

В частности, если [math]X = \{x\}[/math], то [math]S(X) = \prod \limits_{i=1}^{d} x_i[/math].

Задача: найти точное значение гиперобъема [math]S(X)[/math] множества из [math]n[/math] точек [math]d[/math]-мерного пространоства.

Алгоритм включения-исключения (Inclusion-Exclusion Algorithm, IEA)

Самый простой алгоритм нахождения гиперобъема базируется на идее комбинаторной формулы включения-искючения. Все множество [math]X[/math] представляется в виде объединения [math]n[/math] гиперкубов ([math]X^i[/math]), соответствующих отдельным точкам [math]x^i[/math].

После этого объем всего множества вычисляется по формуле:
[math] S(X) = \sum \limits_{I \in 2^n} (-1)^{|I|+1} S(\bigcap \limits_{ j \in I} X^j) [/math]

Объем пересечения гиперкубов легко считается как произведение по каждой координате минимального значения этой координаты среди всех точек, которым соответствуют гиперкубы.

Таким образом, в этом алгоритме перебираются все подмножества точек множества [math]X[/math], для каждого множества находится гиперобъем пересечения соответствующих гиперкубов и он прибавляется с соответствующим знаком к ответу. Время работы этого алгоритма составляет [math]O(n 2^n)[/math].

Алгоритм LebMeasure

Алгоритм LebMeasure обрабатывает точки множества [math]X[/math] по очереди. Для каждой очередной точки [math]x[/math] находится объем некоторого максимального по включению гиперкуба, доминируемого эксклюзивно только этой точкой [math]x[/math] и она заменяется на некоторое множество порожденных точек, которые доминируют оставшуюся область, доминировшуюся до этого точкой [math]x[/math].

Например, если изначально было четыре точки в трехмерном пространстве
[math](6, 7, 4), (9, 5, 5), (1, 9, 3), (4, 1, 9)[/math],
то точка [math](6, 7, 4)[/math] эксклюзивно доминирует куб с одним концов в [math](6, 7, 4)[/math], а другим - в [math](4, 5, 3)[/math]. После добавления объема этого куба в ответу, точка [math](6, 7, 4)[/math] порождает три точки:
[math](4, 7, 4), (6, 5, 3), (6, 7, 3)[/math].
При этом, точка [math](6, 5, 4)[/math] доминируется точкой [math](9, 5, 5)[/math] и сразу удаляется из множества [math]X[/math].

Обработка точек продолжается, пока все точки не будут обработаны. Таким образом, время работы алгоритмы напрямую зависит от количества порожденных точек. Легко заметить, что таких точек не более, чем [math]n^d[/math], поскольку каждая координата каждой порожденной точки равна соответствующей координате некоторой точки исходного множества [math]X[/math].

К сожалению, эта верхняя оценка является достижимой. Например, если исходное множество [math]X[/math] имеет вид: [math](1, n, n, ..., n), (2, n - 1, n - 1, ..., n - 1), ..., (n, 1, 1, ..., 1)[/math], и точки обрабатываются в этом порядке, то всего будет обработано [math]n^{d-1}[/math] точка, что показано в [1]. Правда, если в этом примере точки обрабатываются в обратном порядке, то суммарное количество обработанных точек линейно зависит от [math]n[/math] и [math]d[/math]. Тем не менее, существуют примеры, для которых любой порядок обработки приводит к экспоненциальной зависимости числа порожденных точек от размерности пространства [math]d[/math] и близок к [math]n^d[/math] [1].

Алгоритм Hypervolume by Slicing Objectives (HSO)

Под Objectives в названии данного алгоритма имеются в виду координаты пространства [math]R^d[/math].

Если алгоритм LebMeasure по очереди рассматривает все точки, то алгоритм HSO рассматривает по очереди все координаты, сводя задачу к меньшей на единицу размерности.

Изначально все точки сортируются по первой координате. Значения этой координаты используются для расслоения(разрезания) всего множества на [math]n[/math] частей, внутри каждой из которых при движении вдоль первой координаты форма разреза перпендикулярно оси первой координаты не меняется. Таким образом, для подсчета объема каждой части необходимо найти объем разреза и умножить длину части вдоль первой координаты. При этом получившийся разрез имеет на единицу меньшую размерность. Заметим, что после сортировки и расслоения первая часть содержит все [math]n[/math] точек, вторая - все, помимо точки с минимальной координатой, вдоль которой происходит расслоение и т.д., а последняя часть содержит только одну точку с максимальной этой координатой.

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

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

Время работы алгоритма напрямую зависит от суммарного количества частей, на которые будет разбито исходное множество. По аналогичным предыдущему алгоритму рассуждениям легко показывается, что частей не более [math]n^d[/math]. Тем не менее, существует более точная оценка.

Теорема:
Суммарное количество частей, полученных алгоритмом HSO, не превышает
[math]f(n, d) = {n + d - 2 \choose d - 1}[/math].
Доказательство:
[math]\triangleright[/math]
База:
[math]f(n, 1) = 1[/math].
Также, из алгоритма расслоения следует, что из части с [math]n[/math] точками будет получено по одной части для каждого [math]i = 1...n[/math], то есть:
[math]f(n, d) = \sum \limits_{i = 1}^{n}f(i, d - 1)[/math].
1) Покажем, что:
[math]{x \choose y} = {x - r \choose y} + \sum \limits_{i = 1}{r} {x - i \choose y - 1}[/math].
Индукция по [math]r[/math]. База:
[math]{x \choose y} = {x - 1 \choose y} + {x - 1 \choose y - 1}[/math].
2)
[math]\triangleleft[/math]

Таким образом, на этот алгоритм получена более низкая оценка времени работы, чем на предыдущий, и это подтверждается на практике [1].

Сведение к задаче KMP (Klee's Measure Problem)

Задача KMP состоит в нахождении объема объединения прямоугольных гиперпараллелепипедов в [math]d[/math]-мерном пространстве. Как показано в описании алгоритма IEA, исходная задача легко сводится к этой, если каждой точке поставить в соответствие гиперкуб с одной вершиной в центре координат, а противоположной - в этой точке.

Существует несколько алгоритмов решения задачи KMP, самый оптимальный из которых использует идеи сканирующей гиперплоскости, корневой эвристики и КД-дерево, и позволяет решать задачу за время [math]O(n^{d/2}\log n)[/math]. Рассмотрим его.

Для начала изложим идею сканирующей гиперплоскости. Рассмотрим всевозможные значения [math]d[/math]-ой координаты у точек множества [math]X[/math]. Возьмем гиперплоскость, перпендикулярную оси [math]d[/math]-ой координаты, будем ее двигать по этим значениям от минимального до максимального и рассматривать проекцию всех гиперкубов на эту гиперплоскость. Заметим, что между точками проекция меняться не будет, а в каждой точке будут появляться или исчезать проекции некоторых гиперкубов. Поэтому, если уметь эффективно пересчитывать объем проекции при каждом появлении/исчезновении и прибавлять это значение, умноженное на расстояние между последовательными значениями [math]d[/math]-ой координаты, то можно легко посчитать суммарный гиперобъем. Как раз для эффективного пересчета используется такая структура, как КД-дерево.

Теперь изложим идею алгоритма на примере трехмерного пространства. Будем считать, что сканирующая плоскость двигается перепендикулярно оси [math]OZ[/math]. В каждый момент проекция всех параллелепипедов на эту плоскость предствляет собой множество прямоугольников и необходимо уметь обрабатывать следующие три запроса:

  1. добавить прямоугольник
  2. удалить прямоугольник
  3. посчитать площадь объединения всех прямоугольников


Определение:
КД-деревом называется сбалансированное двоичное дерево, где каждой вершине [math]\alpha[/math] соответствует некоторая область [math]C_{\alpha}[/math] [math]d[/math]-мерного пространстве, удовлетворяющая следующим свойствам:
  1. Корневой вершине [math]root[/math] соответствует [math]C_{root}[/math] - все пространство.
  2. Каждое [math]C_{\alpha}[/math] является гиперпараллелепипедом (возможно бесконечным в некоторых направлениях).
  3. Для каждой вершины [math]\alpha[/math] с детьми [math]\beta[/math] и [math]\gamma[/math] верно, что области [math]C_{\beta}[/math] и [math]C_{\gamma}[/math] не пересекаются и [math]C_{\alpha} = C_{\beta} \cup C_{\gamma}[/math].


Будем хранить прямоугольники в КД-дереве следующим образом:

  1. Для каждого листа [math]\alpha[/math] будем хранить все прямоугольники, которые пересекают внутреннюю часть области [math]C_{\alpha}[/math].
  2. Для каждой внутренней вершины [math]\alpha[/math] будем считать число [math]Cover_{\alpha}[/math] - количество прямоугольников, которые полностью покрывают область [math]C_{\alpha}[/math], но не полностью покрывают область родителя этой вершины [math]C_{father(\alpha)}[/math].

Также для каждой вершины будем хранить значение площади пересечения области этой вершины со всеми прямоугольниками [math]M[/math], которое определяется следующим образом:

  1. Для каждого листа [math]M[/math] равно площади пересечения всех прямоугольников с областью этого листа.
  2. Для каждой внутренней вершины [math]\alpha[/math] если [math]Cover_{\alpha} \gt 0[/math], тогда [math]M[/math] равно площади всех области [math]C_{\alpha}[/math], иначе [math]M[/math] равно сумме этих значений для двух сыновей этой вершины.

Таким образом, значение для корневой вершины [math]M_{root}[/math] и является искомой площадью объединения всех прямоугольников.

Рассмотрим операцию добавления прямоугольника (box) в КД-дерево.

 procedure Insert(box, [math]\alpha[/math])
 if [math]\alpha[/math] - лист then
   добавить box в эту вершину
   пересчитать [math]M_{\alpha}[/math]
 elseif box покрывает область [math]C_{\alpha}[/math] then
   [math]Cover_{\alpha} = Cover_{\alpha} + 1[/math]
   [math]M_{\alpha} = [/math] объем области [math]C_{\alpha}[/math]
 elseif box пересекает область [math]C_{\alpha}[/math] then
   Insert(box, leftson([math]\alpha[/math]))
   Insert(box, rightson([math]\alpha[/math]))
   if [math]Cover_{\alpha} \gt  0 [/math] then
     [math]M_{\alpha} = [/math] объем области [math]C_{\alpha}[/math]
   else
     [math]M_{\alpha} = M_{leftson(\alpha)} + M_{rightson(\alpha)}[/math]

Аналогично устроена операция удаления прямоугольника - она выполняет обратные действия.