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.


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.

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.