Algoritmo similar de ancestral comum mais baixo para um gráfico

7

Estou trabalhando em um sistema de tipos e encontrei um problema que parece semelhante ao menor ancestral comum. Dados dois tipos, preciso encontrar a menor sequência de conversões que resultará no mesmo tipo de destino. Se eu tivesse uma árvore de tipos simples, sei como obter o resultado, mas infelizmente tenho uma estrutura gráfica um pouco mais complexa.

Esse gráfico tem alguns pontos-chave. É unidirecional e nenhum loop é formado. Devido a um número ilimitado de tipos, no entanto, não pode ser produzido estaticamente. A distância de um caminho é geralmente bastante baixa. "Parece" mais uma árvore com várias bordas de atalho.

Inicialmente, olhei para o menor ancestral comum, mas ele é descrito principalmente como um algoritmo de árvore. Ainda não perdi a esperança de poder adaptá-lo. A outra possibilidade seria um algoritmo de localização de caminho mais genérico.

Espero que alguém tenha visto esse problema antes, ou um problema semelhante, e possa me dar algumas referências sobre como abordá-lo ainda mais. Parece familiar o suficiente para presumir que algo deve existir e estou apenas procurando os termos / nomes errados.


Aqui está minha tentativa de descrever isso de maneira mais formal.

Haja um gráfico G={V} de modo que cada vértice tenha um conjunto de arestas de saída V={E=Vx}. Observe que, como o gráfico é dinâmico, possivelmente infinito, não há como construir a formaG={V,E=(Vx,Vy)} para o gráfico inteiro.

Um caminho é formado a partir de um vértice, seguindo qualquer uma das arestas disponíveis desse nó. Pnmx=Vn,...,Vm. O comprimento desse caminho é igual ao número de vértices na sequência. Não há ciclo possível. O conjunto de todos os caminhos entre dois nós é expresso comoPnm={Vn,...,Vm}.

Observe que Pnmpode ser determinado como vazio em um número finito de etapas. Enumerando todo oPnm o conjunto não é praticamente possível.

O problema é encontrar o caminho mais curto de dois vértices para um terceiro vértice. Ou seja, dadoVa,Vb, encontrar Vc de modo que caminhos Pacx e Pbcy existe e length(Pacx)+length(Pbcy) é mínimo.

edA-qa mort-ora-y
fonte
11
Um gráfico direcionado sem ciclos direcionados é conhecido como DAG. No seu caso, você diz que o gráfico não contém loops. Pode conter ciclos?
Yuval Filmus
11
Além disso, você pode indicar seu problema de maneira mais formal? Aqui está uma possibilidade Dadax,y, você está procurando um nó z que minimiza d(z,x)+d(z,y), Onde dé a distância direcionada. Além disso, dado um nó, você pode enumerar todas as arestas apontando para ele, em outras palavras, todos os ancestrais imediatos?
Yuval Filmus
11
Eu teria assumido que é preciso minimizar maxd(z,x),d(z,y). Seu ancestral mais baixo existe em todos os casos (por exemplo: existe uma "raiz" como java.lang.Object)?
frafl
Editado. Dado um nó, sim, você pode enumerar todos os seus ancestrais imediatos. Não, não há raiz comum e não há garantia de que dois tipos tenham um ancestral em comum.
EDA-qa MORT-ora-y
11
Observe que "você pode enumerar todos os seus ancestrais imediatos" não implica que o número de ancestrais imediatos seja finito, o que provavelmente é o que você deseja dizer. Se a regra "encontrar o caminho mais curto" é apenas uma maneira ad hoc de resolver ambiguidades no sistema de tipos, pode ter algumas propriedades indesejáveis. Se, por outro lado, você puder mostrar que ele não possui propriedades indesejáveis ​​se usado adequadamente, isso seria um resultado interessante. Caso contrário, o "menor limite superior" no poset seria a interpretação mais natural do "menor ancestral comum".
Thomas Klimpel 19/03/2013

Respostas:

5

Se o ancestral comum mais baixo de dois tipos sempre existir e for único, sua estrutura será um junção-semilático. É possível calcular o ancestral comum mais baixo possível, mas a pior complexidade de tempo de execução não é tão boa quanto eu esperava intuitivamente. Eu fiz uma pergunta relacionada há algum tempo, mas fiquei com preguiça de escrever uma resposta depois de encontrar a solução relevante na "literatura". Acabei de escrever a resposta agora, e ela começa da seguinte maneira:

Este post no blog sobre teoria das redes possui uma seção de referência útil, que contém, entre outros, "Teoria da Rede com Aplicações", de Vijay K. Garg. O Capítulo 2 "Representando Posets" descreve algumas estruturas de dados para representar posets e discute como calcular a junção (x, y) usando essa estrutura de dados.

Aqui está a parte relevante do capítulo 2.3.1:

Agora damos uma O(n+|e|) algoritmo para calcular a junção de dois elementos x e y. O algoritmo retornanullse a junção não existir. Primeiro, assumimos que estamos usando a relação de cobertura. Para calcularjoin(x,y), procedemos da seguinte maneira:

  • Etapa 0: Colora todos os nós em branco.
  • Etapa 1: Colorir todos os nós acessíveis xcomo cinza. Isso pode ser feito por um BFS ou um DFS a partir do nóx.
  • Etapa 2: executar um BFS / DFS a partir do nó y. Colora todos os nós cinza alcançados em preto.
  • Etapa 3: Agora determinamos para cada nó preto z, o número de nós pretos que apontam para z. Ligue para este númeroinBlack[z] para qualquer nó z. Esta etapa pode ser realizada emO(n+|e|) percorrendo as listas de adjacência de todos os nós pretos e mantendo as contagens cumulativas de inBlack array.
  • Etapa 4: contamos o número de nós pretos z com inBlack[z] igual a 0. Se houver exatamente um nó, retornamos esse nó como resposta. Caso contrário, retornamosnull.
Thomas Klimpel
fonte
Esta resposta interpreta o "ancestral comum mais baixo" em relação à ordem parcial definida pelo DAG. Para a leitura em relação aos comprimentos de caminho, não temos mais uma semi-treliça, mas o algoritmo ainda pode ser adaptado usando apenas o BFS e intercalando as duas pesquisas adequadamente. A interpretação do poset ainda é útil para determinar se existe pelo menos um candidato "menor ancestral comum".
Thomas Klimpel 19/03/2013