Фон
У меня есть упорядоченный набор точек данных, сохраненных как TreeSet<DataPoint>
. Каждая точка данных имеет position
и Set
объектов Event
(HashSet<Event>
).
Есть 4 возможных объекта Event
A
, B
, C
и D
. Каждый DataPoint
имеет 2 из них, например. A
и C
, кроме первого и последнего DataPoint
объектов в наборе, которые имеют T
размера 1.
Мой алгоритм должен найти вероятность нового DataPoint
Q
в позиции x
с Event
Q
в этом наборе.
Я делаю это, вычисляя значение S
для этого набора данных, затем добавляя Q
к множеству и вычисляя S
снова. Затем я разделяю второй S
на первый, чтобы выделить вероятность для нового DataPoint
Q
.
Алгоритм
Формула для вычисления S
:
http://mathbin.net/equations/105225_0.png
где
http://mathbin.net/equations/105225_1.png
http://mathbin.net/equations/105225_2.png
для http://mathbin.net/equations/105225_3.png
и
http://mathbin.net/equations/105225_4.png
http://mathbin.net/equations/105225_5.png - это дорогостоящая функция вероятности, которая зависит только от ее аргументов и ничего другого (и http://mathbin.net/equations/105225_6.png), http://mathbin.net/equations/105225_7.png - это последний DataPoint
в наборе ( right node), http://mathbin.net/equations/105225_8.png - это первый DataPoint
(lefthand node), http://mathbin.net/equations/105225_9.png - самый правый DataPoint
, который не является node, http://mathbin.net/equations/105225_10.png является DataPoint
, http://mathbin.net/equations/105225_12.png является Set
событий для этого DataPoint
.
Таким образом, вероятность для Q
с Event
Q
равна:
http://mathbin.net/equations/105225_11.png
Реализация
Я реализовал этот алгоритм в Java так:
public class ProbabilityCalculator {
private Double p(DataPoint right, Event rightEvent, DataPoint left, Event leftEvent) {
// do some stuff
}
private Double f(DataPoint right, Event rightEvent, NavigableSet<DataPoint> points) {
DataPoint left = points.lower(right);
Double result = 0.0;
if(left.isLefthandNode()) {
result = 0.25 * p(right, rightEvent, left, null);
} else if(left.isQ()) {
result = p(right, rightEvent, left, left.getQEvent()) * f(left, left.getQEvent(), points);
} else { // if M_k
for(Event leftEvent : left.getEvents())
result += p(right, rightEvent, left, leftEvent) * f(left, leftEvent, points);
}
return result;
}
public Double S(NavigableSet<DataPoint> points) {
return f(points.last(), points.last().getRightNodeEvent(), points)
}
}
Итак, чтобы найти вероятность Q
при x
с Q
:
Double S1 = S(points);
points.add(Q);
Double S2 = S(points);
Double probability = S2/S1;
Проблема
Поскольку реализация на данный момент соответствует математическому алгоритму. Однако на практике это оказывается не очень хорошей идеей, так как f
вызывает себя дважды для каждого DataPoint
. Итак, для http://mathbin.net/equations/105225_9.png, f
вызывается дважды, затем для n-1
f
вызывается дважды дважды для каждого из предыдущие вызовы и т.д. и т.д. Это приводит к сложности O(2^n)
, что довольно ужасно, учитывая, что в каждом Set
может быть более 1000 DataPoints
. Поскольку p()
не зависит от всего, кроме его параметров, я включил функцию кеширования, где, если p()
уже был рассчитан для этих параметров, он просто возвращает предыдущий результат, но это не решает проблему сложности с присущей сложностью. Я что-то пропустил здесь в отношении повторных вычислений, или это сложность, неизбежная в этом алгоритме?