Maneiras de encontrar o objetivo. O papel do acaso

1. Introdução


A pesquisa pode ser complexa ou simples. Quando não é conhecido (ou apenas parcialmente conhecido) tanto o objetivo em si quanto a maneira de alcançá-lo, o acaso é importante

O objetivo do artigo de pesquisa é comparar os métodos de encontrar o alvo como móvel (objeto amarelo) e imóvel.

Estes métodos:

  • Pesquisa aleatória (objeto vermelho)
  • Pesquisa aleatória com memória (objeto azul)
  • Pesquisa aleatória com memória e hierarquia (objeto verde)
  • Procure a primeira rota (objeto roxo)
  • Procure uma rota curta (objeto marrom)

Na Fig. 1, esses objetos são mostrados. Código de programa totalmente publicado no github



2. A parte principal


2.1 Classe P - Pesquisa Aleatória

O construtor inicializa os atributos e variáveis ​​da classe: janela principal, cor, coordenada ye x, contador, dicionário visitado, destino, dicionário de hierarquia, dicionário de vizinhos. O método init_3_dict preenche três dicionários. O método show pinta a célula na cor desejada. O método update atualiza o objeto. O método top_show cria uma janela de nível superior e mostra quantas etapas foram tomadas para o destino.

class P(): def __init__(self, root, color, node, target, maps, ban): self.root = root self.color = color self.y = node[0] self.x = node[1] P.target = target self.count = 0 self.visit = {} P.hierarchy = {} P.neighbor = {} self.init_3_dict(maps, ban) 

A função is_en é declarada no método init_3_dict, que verifica se a coordenada não foi banida e não vai além do mapa.

 def init_3_dict(self, maps, ban): def is_en(yx): if yx[0] < 0 or yx[0] > len(maps)-1: return if yx[1] < 0 or yx[1] > len(maps[0])-1: return if yx in ban: return return True 

Em um ciclo, no dicionário visitado com a tecla de coordenadas, escreva o valor inicial zero. No dicionário da hierarquia com a mesma chave, escreva o nome hierárquico dessa coordenada. Em seguida, preenchemos o dicionário de vizinhos chamando a função is_en.

 for y in range(len(maps)): for x in range(len(maps[0])): self.visit[(y,x)] = 0 P.hierarchy[(y,x)] = maps[y][x] n = [] if is_en((y-1,x)): n.append((y-1,x)) if is_en((y+1,x)): n.append((y+1,x)) if is_en((y,x-1)): n.append((y,x-1)) if is_en((y,x+1)): n.append((y,x+1)) P.neighbor[(y,x)] = n 

O método show pinta uma célula com coordenadas y, x na cor desejada.

 def show(self, y, x, color): lb = Label(text=" ", background = color) lb.configure(text=P.hierarchy[(y,x)] ) lb.grid(row=self.y, column=self.x, ipadx=10, ipady=5, padx=1, pady=1) 

O método move move o objeto. Nas variáveis ​​y, x, escrevemos a coordenada do vizinho, que é selecionada aleatoriamente na lista de vizinhos. Em seguida, redesenhamos com as novas coordenadas.

Nós aumentamos o contador. Verifique se o objetivo foi alcançado. Se o objetivo for alcançado, na variável da classe J.disable, escrevemos corretamente. Chamamos o método top_show ().

 def move(self): v = [] for i in P.neighbor[(self.y, self.x)]: v.append(i) y,x = random.choice(v) self.show(self.y, self.x, 'white') self.y = y self.x = x self.show(y, x, self.color) self.count +=1 if P.target == P.hierarchy[(self.y, self.x)]: J.disable = True self.top_show() 

O método de atualização chama mover e atualiza a cada meio segundo.

 def update(self): self.move() self.root.after(500, self.update) 

O método top_show exibe os resultados.

 def top_show(self): top = Toplevel() lbt = Label(top, text=self.color + " = " + str(self.count)) lbt.pack() top.mainloop() 

2.2 Classe M - Pesquisa Aleatória em Memória

O construtor chama o construtor da classe pai e aumenta o valor da célula do campo para onde estamos indo. O método move move o objeto. O método de escolha retorna a coordenada que o algoritmo de pesquisa aleatória com memória selecionou.

No método de movimentação, chame o método de escolha. Caso contrário, seu trabalho é semelhante ao método dos pais.

 def move(self): yx = self.choice((self.y, self.x)) 

O método de escolha itera sobre as coordenadas dos vizinhos e adiciona tuplas à lista v. O primeiro elemento da tupla será a coordenada do vizinho, o segundo - quantas vezes ele foi visitado. Depois, classificamos de pequeno a grande. Classificamos todas as tuplas e, na lista v, deixamos apenas aquelas que ocorreram quantas vezes foram registradas na primeira tupla. Selecione aleatoriamente qualquer um deles.

 def choice(self, yx): v = [] for i in P.neighbor[yx]: v.append((i, self.visit[i])) v.sort(key = lambda x: x[1], reverse = False) v = [i for i in v if v[0][1] == i[1]] v = random.choice(v) self.visit[v[0]] += 1 return v[0] 

2.3 Classe N - pesquisa aleatória com memória e hierarquia.

O método de escolha seleciona as tuplas que mais se aproximam do nome hierárquico do destino. Se essa correspondência for a mesma, as coordenadas menos visitadas serão selecionadas.

O construtor chama o construtor do pai e inicializa o atributo de coincidência, o número de correspondências de caracteres do nome hierárquico com o destino.

 def __init__(self, root, color, node, target, maps, ban): super().__init__(root, color, node, target, maps, ban) self.coincidence = 0 

O método de escolha no loop grava o nome hierárquico da coordenada atual do vizinho. A variável r armazena o número de correspondências dessa variável com o destino. Se o número de correspondências r for maior, a coincidência será substituída. Nesse caso, a tupla (coordenadas, número de visitas) da lista v é gravada na lista d. Se r é igual a coincidência, então em d adicionamos uma tupla de v.

 def choice(self, yx): v = [] for i in P.neighbor[yx]: v.append((i, self.visit[i])) d = [] for l in v: c = P.hierarchy[l[0]] r = 0 for i in range(len(P.target)): if c[i] == P.target[i]: r +=1 else: break if r > self.coincidence: self.coincidence = r d = [l] if r == self.coincidence: d.append(l) if d: v = d v.sort(key = lambda x: x[1], reverse = False) v = [i for i in v if v[0][1] == i[1]] v = random.choice(v) self.visit[v[0]] += 1 return v[0] 

2.4 Classe K - procure uma rota e procure a rota mais curta.

O construtor grava coordenadas finais na variável final. Se o parâmetro curto for False, chamaremos a pesquisa de rota. Caso contrário, encontraremos o caminho mais curto.

O método find_path adiciona a coordenada atual à rota. Se a meta for atingida, retornará a rota. Separamos todos os vizinhos. Se não houver vizinho no caminho, então nos chamamos recursivamente. E o fato de o método retornar é gravado em newpath. A primeira rota encontrada será newpath. A diferença entre o método find_short_path é que, se o comprimento do caminho novo for maior ou igual ao comprimento do menor, o menor será substituído.

 def find_path(self, node, end, path=[]): path = path + [node] if node == end: return path for v in P.neighbor[node]: if v not in path: newpath = self.find_path(v, end, path) if newpath: return newpath 

2.5 A classe J é um alvo em movimento.

Um objeto da classe J se move como a classe P. Se a variável da classe J.disable for verdadeira, o objeto será interrompido.

2.6 Função principal.

Crie a janela principal. Na variável de destino, escreva o nome hierárquico do destino. A lista de proibições contém as coordenadas das células proibidas. Na lista de mapas, o próprio mapa. No loop, desenhamos um mapa. Crie objetos de classe. Em seguida, chamamos a função update, que atualiza os objetos.

3. Conclusões


Foram realizadas cinco experiências, tanto para um alvo em movimento quanto para um imóvel.

A Tabela 1 mostra que o melhor algoritmo é a rota mais curta. O segundo mais eficaz é uma pesquisa aleatória com memória e hierarquia. O pior é a pesquisa aleatória.

Tabela 1. Alvo fixo

imagem

No caso de um alvo em movimento, os resultados são diferentes. Os piores algoritmos foram aqueles que inicialmente calcularam a rota para a meta. Na tabela 2, um traço indica que o objetivo não foi alcançado. Brown acabou sendo pior que Violet. Pior, porque Violet tem uma trajetória mais longa (a chance de atingir um alvo em movimento é maior). O melhor algoritmo ao procurar um alvo em movimento é uma pesquisa aleatória com memória e hierarquia. Em segundo lugar, é uma pesquisa aleatória com memória.

Tabela 2. Alvo Móvel

imagem

Se não se sabe se o destino está se movendo ou não, é melhor usar o algoritmo de pesquisa aleatória com memória e hierarquia ou apenas pesquisa aleatória com memória.

4. Conclusão


A aleatoriedade é importante se a busca por um alvo ocorrer diante da incerteza. A pesquisa é reduzida se os dados forem apresentados hierarquicamente. A memória, é claro, também é valiosa.

Source: https://habr.com/ru/post/pt479414/


All Articles