Направленный граф вероятности — алгоритм сокращения циклов?

Рассмотрим ориентированный граф, который проходит от первого узла 1 в некоторые конечные узлы (у которых больше нет исходящих ребер). Каждое ребро в графе имеет вероятность, связанную с ним. Суммирование вероятностей для каждого возможного пути ко всем возможным конечным узлам возвращает 1, (Это означает, что мы гарантированно достигнем одного из конечных узлов в конце концов.)

Проблема была бы простой, если бы петли в графе не существовали. К сожалению, на графике могут возникать довольно извилистые циклы, которые можно обходить бесконечное количество раз (вероятность уменьшается мультипликативно с каждым обходом цикла, очевидно).

Существует ли общий алгоритм для определения вероятностей достижения каждого из конечных узлов?

Особенно неприятный пример:

Мы можем представить ребра в виде матрицы (вероятность перехода из строки (узла) x грести (узел) y находится в записи (x,y))

{{0, 1/2, 0, 1/14, 1/14, 0, 5/14},
{0, 0, 1/9, 1/2, 0, 7/18, 0},
{1/8, 7/16, 0, 3/16, 1/8, 0, 1/8},
{0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}}

Или как ориентированный граф:

введите описание изображения здесь

Начальный узел 1 синий, последние узлы 5,6,7 зеленые. Все ребра помечены вероятностью их прохождения, начиная с узла, откуда они берутся.

Это имеет восемь разных путей от начального узла 1 до конечных узлов:

{{1/14, {1, 5}}, {5/14, {1, 7}}, {7/36, {1, 2, 6}},
{1/144, {1, 2, 3, 5}}, {1/144, {1, 2, 3, 7}},
{1/36, {1, 4, 2, 6}}, {1/1008, {1, 4, 2, 3, 5}}, {1/1008, {1, 4, 2, 3, 7}}}

(Обозначение для каждого пути: {вероятность, последовательность посещенных узлов})

И есть пять различных петель:

{{1/144, {2, 3, 1}}, {7/144, {3, 2}}, {1/2, {4, 2}},
{1/48, {3, 4, 2}}, {1/1008, {4, 2, 3, 1}}}

(Обозначение для циклов: {вероятность пройти цикл один раз, последовательность посещенных узлов}).

Если бы только эти циклы могли быть решены для получения эффективного древовидного графа, проблема была бы решена.

Любой намек на то, как справиться с этим?

Я знаком с Java, C ++ и C, поэтому предложения на этих языках предпочтительнее.

6

Решение

Я не эксперт в области цепей Маркова, и, хотя я думаю, что алгоритмы известны для той проблемы, которую вы представляете, мне трудно их найти.

Если от этого направления не получится никакой помощи, тогда вы можете подумать о прокрутке самостоятельно. Я вижу здесь как минимум два разных подхода:

  1. Моделирование.

Изучите, как состояние системы развивается со временем, начиная с того, что система находится в состоянии 1 с вероятностью 100%, и выполняя множество итераций, в которых вы применяете свои вероятности перехода для вычисления вероятностей состояния, полученного после выполнения шага. Если по крайней мере один конечный («поглощающий») узел может быть достигнут (с ненулевой вероятностью) из каждого узла, то через достаточное количество шагов вероятность того, что система находится в каком-либо другом месте, кроме конечного состояния, будет асимптотически уменьшаться до нуля. Вы можете оценить вероятность того, что система завершится в конечном состоянии S, как вероятность того, что она находится в состоянии S после N шаги с верхней границей ошибки в этой оценке, определяемой вероятностью того, что система находится в неконечном состоянии после N шаги.

На практике это то же самое, TrN, где Tr ваша вероятностная матрица перехода, дополненная самоограничениями с вероятностью 100% для всех конечных состояний.

  1. Точные вычисления.

Рассмотрим граф G, такой как вы описали. Учитывая две вершины я а также е, такой, что есть хотя бы один путь из я в е, а также е не имеет исходящих ребер, кроме собственных ребер, мы можем разделить пути из я в е на классы, характеризуемые количеством раз, они посещают я до достижения е. Таких классов может быть бесконечное множество, которые я обозначу Сесли(N), где N представляет количество раз пути в Сесли(N) пересмотреть узел я. Особенно, Сб(0) содержит все простые циклы в G, которые содержат я (осветление: а также другие пути).

Общая вероятность окончания в узле е учитывая, что система пересекает граф G, начиная с узла я дан кем-то

Pr (е|я, G) = Pr (Сесли(0) | G) + Pr (Сесли(1) | G) + Pr (Сесли(2) | G) …

Теперь обратите внимание, что если N > 0, то каждый путь в Сесли(N) имеет форму объединения двух путей с а также T, где с принадлежит Сб(N-1) и T принадлежит Сесли(0). То есть, с это путь, который начинается в узле я и заканчивается в узле я, проходя через я N-1 раз между T путь от я в е это не проходит через я снова. Мы можем использовать это, чтобы переписать нашу формулу вероятности:

Pr (е|я,G) = Pr (Сесли(0) | G) + Pr (Сб(0) | G) * Pr (Сесли(0) | G) + Pr (Сб(1) | G) * Pr (Сесли(0) | G) + …

Но обратите внимание, что каждый путь в Сб(N) является составом N+1 дорожек, принадлежащих Сб(0). Отсюда следует, что Pr (Сб(N) | G) = Pr (Сб(0) | G)N+1, так мы получаем

Pr (е|я) = Pr (Сесли(0) | G) + Pr (Сб(0) | G) * Pr (Сесли(0) | G) + Pr (Сб(0) | G)2 * Pr (Сесли(0) | G) + …

А теперь маленькая алгебра дает нам

Pr (е|я,G) — Pr (Сесли(0) | G) = Pr (Сб(0) | G) * Pr (е|я,Г)

, который мы можем решить для Pr (е|я,Г) чтобы получить

Pr (е|я,G) = Pr (Сесли(0) | G) / (1 — Pr (Сб(0) | G))

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

В частности, пусть S(я, Г) быть множеством наследников вершины я в графе G — то есть множество вершин s такой, что есть грань от я в s в G, и пусть X (G,я) быть подграфом G, образованным удалением всех ребер, которые начинаются в я. Кроме того, пусть пявляется вероятность, связанная с краем (я, sв) в г.

Pr (Сесли(0) | G) = Сумма по s в S(я, Г) из пявляется * Pr (е|s,X (G,я))

Другими словами, вероятность достижения е от я через G без повторного посещения я между ними сумма по всем наследникам я произведения вероятности достижения s от я в один шаг с вероятностью достижения е от s через G, не пересекая какие-либо ребра, исходящие из я. Это относится ко всем е в G, в том числе я.

Теперь обратите внимание, что S(я, Г) и все пявляется Известно, что и проблема вычисления Pr (е|s,X (G,я)) это новый, строго меньший экземпляр исходной проблемы. Таким образом, это вычисление может быть выполнено рекурсивно, и такая рекурсия гарантированно завершится. Тем не менее может потребоваться много времени, если ваш граф сложный, и похоже, что наивная реализация этого рекурсивного подхода будет экспоненциально масштабироваться по количеству узлов. Существуют способы ускорения вычислений в обмен на более высокое использование памяти (т. Е. Запоминание).


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

1

Другие решения

Разъяснение проблемы

Входные данные представляют собой набор из m строк из n столбцов вероятностей, по сути, матрицы m на n, где m = n = количество вершин в ориентированном графе. Строки — это начало, а столбцы — это назначение. На основании упоминания циклов в вопросе мы будем считать, что граф циклический, что в нем существует хотя бы один цикл.

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

Во входных данных вероятности для строк, которые соответствуют вершинам, не принадлежащим T, нормализованы до общего значения 1,0. Предположим свойство Маркова, что вероятности в каждой вершине не меняются со временем. Это исключает использование вероятности для определения приоритетности маршрутов при поиске в графике. 2.

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

Применение вероятности к маршрутам

Вероятность достижения конечной вершины может быть выражена как сумма произведений бесконечной серии.

пT = лим s -> ∞ Σ ∏ Pя, дж,

где s — индекс шага, t — индекс терминальной вершины, i ∈ [1 .. m] и j ∈ [1 .. n]

снижение

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

Возможно несколько первоначальных сокращений.

  1. Первое соображение состоит в том, чтобы перечислить целевую вершину, что легко, поскольку соответствующие строки имеют вероятности ноль.

  2. Следующее соображение состоит в том, чтобы дифференцировать любые дальнейшие сокращения от того, что академическая литература называет неприводимыми подграфами. Алгоритм ниже по глубине запоминает, какие вершины уже были посещены при построении потенциального маршрута, поэтому его можно легко модифицировать, чтобы определить, какие вершины участвуют в циклах. Тем не менее, рекомендуется использовать существующие хорошо проверенные и проверенные библиотеки графов, чтобы идентифицировать и охарактеризовать подграфы как неприводимые.

Математическое уменьшение неприводимых частей графика может быть или не быть правдоподобным. Рассмотрим начальную вершину A и единственную завершающую вершину B в графе, представленном как {A-> C, C-> A, A-> D, D-> A, C-> D, D-> C, C-> B, D-> B}.

Хотя можно свести граф к отношениям вероятностей, отсутствующим в циклах, через вершину A, вершину A нельзя удалить для дальнейшего сокращения, не изменив ни вероятности вершин, выходящих из C и D, ни допустив, чтобы обе суммы вероятностей ребер, выходящих из C и D, были меньше чем 1.0.

Конвергентная ширина Первый обход

Первый обход в ширину, который игнорирует повторное посещение и позволяет циклам выполнять итерации с индексом шага s, а не с некоторыми фиксированными sМаксимум но до некоторой достаточно устойчивой и точной точки в сходящемся тренде. Этот подход особенно необходим, если циклы перекрываются, создавая бифуркации в более простой периодичности, вызванной одним циклом.

Σ PsΔ s.

Для установления разумной сходимости при увеличении s необходимо определить желаемую точность в качестве критерия для завершения алгоритма сходимости и метрики для измерения точности, рассматривая долгосрочные тренды в результатах во всех конечных вершинах. Может быть важно предоставить критерии, в которых сумма вероятностей конечных вершин близка к единице в сочетании с метрикой сходимости тренда, как для проверки работоспособности, так и для критериев точности. На практике могут потребоваться четыре критерия сходимости 3.

  1. Для каждой вершины вероятность схождения тренда вероятности вершины
  2. Средняя вероятность схождения тренда дельта
  3. Сходимость полной вероятности на единицу
  4. Общее количество шагов (чтобы ограничить глубину по практическим соображениям)

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

Пример цикла, устойчивый к глубине Первый алгоритм

Существуют более эффективные алгоритмы, чем следующий, но он достаточно понятен, он компилируется без предупреждения с помощью C ++ -Wall и выдает желаемый результат для всех конечных и допустимых ориентированных графов и возможных начальных и конечных вершин. 4. Матрицу в форме, указанной в вопросе, легко загрузить с помощью метода addEdge. 5.

#include <iostream>
#include <list>

class DirectedGraph {

private:
int miNodes;
std::list<int> * mnpEdges;
bool * mpVisitedFlags;

private:
void initAlreadyVisited() {
for (int i = 0; i < miNodes; ++ i)
mpVisitedFlags[i] = false;
}

void recurse(int iCurrent, int iDestination,
int route[], int index,
std::list<std::list<int> *> * pnai) {

mpVisitedFlags[iCurrent] = true;
route[index ++] = iCurrent;

if (iCurrent == iDestination) {
auto pni = new std::list<int>;
for (int i = 0; i < index; ++ i)
pni->push_back(route[i]);
pnai->push_back(pni);

} else {
auto it = mnpEdges[iCurrent].begin();
auto itBeyond = mnpEdges[iCurrent].end();
while (it != itBeyond) {
if (! mpVisitedFlags[* it])
recurse(* it, iDestination,
route, index, pnai);
++ it;
}
}

-- index;
mpVisitedFlags[iCurrent] = false;
}

public:
DirectedGraph(int iNodes) {
miNodes = iNodes;
mnpEdges = new std::list<int>[iNodes];
mpVisitedFlags = new bool[iNodes];
}

~DirectedGraph() {
delete mpVisitedFlags;
}

void addEdge(int u, int v) {
mnpEdges[u].push_back(v);
}

std::list<std::list<int> *> * findRoutes(int iStart,
int iDestination) {
initAlreadyVisited();
auto route = new int[miNodes];
auto pnpi = new std::list<std::list<int> *>();
recurse(iStart, iDestination, route, 0, pnpi);
delete route;
return pnpi;
}
};

int main() {

DirectedGraph dg(5);

dg.addEdge(0, 1);
dg.addEdge(0, 2);
dg.addEdge(0, 3);
dg.addEdge(1, 3);
dg.addEdge(1, 4);
dg.addEdge(2, 0);
dg.addEdge(2, 1);
dg.addEdge(4, 1);
dg.addEdge(4, 3);

int startingNode = 2;
int destinationNode = 3;

auto pnai = dg.findRoutes(startingNode, destinationNode);

std::cout
<< "Unique routes from "<< startingNode
<< " to "<< destinationNode
<< std::endl
<< std::endl;

bool bFirst;
std::list<int> * pi;
auto it = pnai->begin();
auto itBeyond = pnai->end();
std::list<int>::iterator itInner;
std::list<int>::iterator itInnerBeyond;
while (it != itBeyond) {
bFirst = true;
pi = * it ++;
itInner = pi->begin();
itInnerBeyond = pi->end();
while (itInner != itInnerBeyond) {
if (bFirst)
bFirst = false;
else
std::cout << ' ';
std::cout << (* itInner ++);
}
std::cout << std::endl;
delete pi;
}

delete pnai;

return 0;
}

Заметки

[1] Неправильно обработанные циклы в алгоритме ориентированного графа будут зависать в бесконечном цикле. (Обратите внимание на тривиальный случай, когда число маршрутов от A до B для ориентированного графа, представленного как {A-> B, B-> A}, равно бесконечности.)

[2] Вероятности иногда используются, чтобы уменьшить стоимость цикла ЦП поиска. Вероятности, в этой стратегии, являются входными значениями для мета-правил в очереди приоритетов, чтобы уменьшить трудоемкие поиски вычислительной задачи (даже для компьютера). Ранняя литература по производственным системам называлась экспоненциальным характером неуправляемых масштабных поисков «Комбинаторные взрывы».

[3] Может быть практически необходимо определить ширину первого вероятностного тренда в каждой вершине и указать удовлетворительную сходимость в терминах четырех критериев.

  1. Δ (ΣΠP)T <= ΔМаксимум ∀ т
  2. Σт = 0T Δ (ΣΠP)T / T <= Δпр
  3. | Σ Σ∏P — 1 | <= тыМаксимум, где u — максимально допустимое отклонение от единицы для суммы конечных вероятностей
  4. s < SМаксимум
[4] При условии, что имеется достаточно вычислительных ресурсов для поддержки структур данных и достаточно времени, чтобы прийти к ответу для данной скорости вычислительной системы.

[5] Вы можете загрузить DirectedGraph dg (7) с входными данными, используя два цикла, вложенных для перебора строк и столбцов, перечисленных в вопросе. Тело внутреннего цикла будет просто условным добавлением ребра.

if (prob != 0) dg.addEdge(i, j);

Переменная проблема п м, п. Наличие маршрута связано только с нулевым / ненулевым статусом.

3

Я понимаю это как следующую проблему:

Учитывая начальное распределение, которое должно быть на каждом узле как вектор b, и матрицу A, в которой хранится вероятность перехода с узла i на узел j на каждом временном шаге, что несколько напоминает матрицу смежности.

Тогда распределение b_1 после одного временного шага равно A x b. Распределение b_2 после двух временных шагов составляет A x b_1. Аналогично, распределение b_n является A ^ n x b.

Для приближения b_infinite мы можем сделать следующее:

Vector final_probability(Matrix A, Vector b,
Function Vector x Vector -> Scalar distance, Scalar threshold){
b_old = b
b_current = A x b
while(distance(b_old,b_current) < threshold){
b_old = b_current
b_current = A x b_current
}
return b_current
}

(Я использовал математические имена переменных для удобства)

Другими словами, мы предполагаем, что последовательность распределений хорошо сходится после заданного порога. Может не быть правдой, но обычно будет работать.

Возможно, вы захотите добавить к этому максимальное количество итераций.

Евклидово расстояние должно хорошо работать как расстояние.

(Это использует концепцию Марковская цепь но это скорее прагматичное решение)

1
По вопросам рекламы [email protected]