def cheapestFirstSearch(self, searchType): """Realiza busca com a estratégia de custo uniforme ou A* conforme escolha realizada na chamada. @param searchType: 0=custo uniforme, 1=A* com heurística hn1; 2=A* com hn2 @return plano encontrado""" # @TODO: Implementação do aluno # Atributos para análise de desempenho treeNodesCt = 0 # contador de nós gerados incluídos na árvore # nós inseridos na árvore, mas que não necessitariam porque o estado # já foi explorado ou por já estar na fronteira exploredDicardedNodesCt = 0 frontierDiscardedNodesCt = 0 # Algoritmo de busca solution = None solutionBox = [] root = TreeNode(parent=None) root.state = self.prob.initialState root.gn = 0 root.hn = 0 root.action = -1 treeNodesCt += 1 # cria FRONTEIRA com estado inicial frontier = [] frontier.append(root) # cria EXPLORADOS - inicialmente vazia explored = [] print("\n*****\n***** INICIALIZAÇÃO ÁRVORE DE BUSCA\n*****\n") print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) while len(frontier): # Fronteira não vazia print("\n*****\n***** Início iteração\n*****\n") printFrontier(frontier) selNode = frontier.pop(0) # retira nó da fronteira selState = selNode.state print("Selecionado para expansão: {}\n".format(selNode)) if self.prob.goalBoxTest(): solutionBox.append(selNode) if self.prob.goalFinalTest(): solution = selNode break explored.append(selNode) printExplored(explored) # Obtem ações possíveis para o estado selecionado para expansão actions = self.prob.possibleActionsWithoutCollaterals( selState) # actions é do tipo [-1, -1, -1, 1, 1, -1, -1, -1] for actionIndex, act in enumerate(actions): if (act < 0): # Ação não é possível continue # INSERE NÓ FILHO NA ÁRVORE DE BUSCA - SEMPRE INSERE, DEPOIS # VERIFICA SE O INCLUI NA FRONTEIRA OU NÃO # Instancia o filho ligando-o ao nó selecionado (nSel) child = selNode.addChild() # Obtem o estado sucessor pela execução da ação <act> sucState = self.prob.suc(selState, actionIndex) child.state = sucState # Custo g(n): custo acumulado da raiz até o nó filho gnChild = selNode.gn + self.prob.getActionCost(actionIndex) if searchType == UNIFORME_COST: child.setGnHn( gnChild, 0 ) # Deixa h(n) zerada porque é busca de custo uniforme elif searchType == A_START_1: child.setGnHn(gnChild, self.hn1(sucState, actionIndex)) elif searchType == A_START_2: child.setGnHn(gnChild, self.hn2(sucState)) child.action = actionIndex # INSERE NÓ FILHO NA FRONTEIRA (SE SATISFAZ CONDIÇÕES) # Testa se estado do nó filho foi explorado alreadyExplored = False # for node in explored: # if child.state == node.state: # alreadyExplored = True # break # Testa se estado do nó filho está na fronteira, caso esteja # guarda o nó existente em nFront nodeFront = None if not alreadyExplored: for node in frontier: if (child.state == node.state): nodeFront = node break # Se ainda não foi explorado if not alreadyExplored: # e não está na fronteira, adiciona à fronteira if nodeFront == None: frontier.append(child) frontier.sort(key=lambda x: x.getFn( )) # Ordena a fronteira pelo f(n), ascendente treeNodesCt += 1 else: # Se já está na fronteira temos que ver se é melhor if nodeFront.getFn() > child.getFn( ): # Nó da fronteira tem custo maior que o filho frontier.remove( nodeFront ) # Remove nó da fronteira (pior e deve ser substituído) nodeFront.remove() # Retira-se da árvore frontier.append( child) # Adiciona filho que é melhor frontier.sort(key=lambda x: x.getFn( )) # Ordena a fronteira pelo f(n), ascendente # treeNodesCt não é incrementado por inclui o melhor e retira o pior else: # Conta como descartado porque o filho é pior que o nó da fronteira e foi descartado frontierDiscardedNodesCt += 1 else: exploredDicardedNodesCt += 1 print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) if (solution != None): print("!!! Solução encontrada !!!") print("!!! Custo: {}".format(solution.gn)) print("!!! Profundidade: {}\n".format(solution.depth)) print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) return buildPlan(solution) else: print("### Solução NÃO encontrada ###") return None
def cheapestFirstSearch(self, searchType): """Realiza busca com a estratégia de custo uniforme ou A* conforme escolha realizada na chamada. @param searchType: 0=custo uniforme, 1=A* com heurística hn1; 2=A* com hn2 @return plano encontrado""" # Atributos para análise de desempenho treeNodesCt = 0 # contador de nós gerados incluídos na árvore # nós inseridos na árvore, mas que não necessitariam porque o estado # já foi explorado ou por já estar na fronteira exploredDicardedNodesCt = 0 frontierDiscardedNodesCt = 0 # Algoritmo de busca solution = None root = TreeNode(parent=None) root.state = self.prob.initialState root.gn = 0 root.hn = 0 root.action = -1 treeNodesCt += 1 # cria FRONTEIRA com estado inicial frontier = [] frontier.append(root) # cria EXPLORADOS - inicialmente vazia explored = {} print("\n*****\n***** INICIALIZAÇÃO ÁRVORE DE BUSCA\n*****\n") print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) while len(frontier): # Fronteira não vazia print("\n*****\n***** Início iteração\n*****\n") #printFrontier(frontier) selNode = frontier.pop(0) # retira nó da fronteira selState = selNode.state print("Selecionado para expansão: {}\n".format(selNode)) # Teste de objetivo if selState == self.prob.goalState: solution = selNode break explored[str(selState.row) + str(selState.col) + str(selState.boxes)] = selState #printExplored(explored) # Obtem ações possíveis para o estado selecionado para expansão actions = self.prob.possibleActions( selState) # actions é do tipo [-1, -1, -1, 1 ] if selNode.gn >= LIMITE_BUSCA and VERIFICA_LIMITE: continue for actionIndex, act in enumerate(actions): if (act < 0): # Ação não é possível continue # INSERE NÓ FILHO NA ÁRVORE DE BUSCA - SEMPRE INSERE, DEPOIS # VERIFICA SE O INCLUI NA FRONTEIRA OU NÃO # Obtem o estado sucessor pela execução da ação <act> sucState = self.prob.suc(selState, actionIndex) # verifica se a acao sucessora bloqueia o tabuleiro if (VERIFICA_ACAO_BLOQUEIO and self.prob.isBlockAction(sucState)): continue # Instancia o filho ligando-o ao nó selecionado (nSel) child = selNode.addChild() child.state = sucState # Custo g(n): custo acumulado da raiz até o nó filho gnChild = selNode.gn + self.prob.getActionCost(actionIndex) if searchType == UNIFORME_COST: child.setGnHn( gnChild, 0 ) # Deixa h(n) zerada porque é busca de custo uniforme elif searchType == HEURISTICA_DISTS: child.setGnHn(gnChild, self.hn(sucState)) elif searchType == HEURISTICA_DISTS_PEN_OBSTACULOS: child.setGnHn(gnChild, self.hnwall(sucState)) elif searchType == H_OPT: child.setGnHn(gnChild, self.hnOptm(sucState)) elif searchType == H_EUCL: child.setGnHn(gnChild, self.hnOptmEucl(sucState)) elif searchType == H_OPT_PEN: child.setGnHn(gnChild, self.hnOptmWall(sucState)) child.action = actionIndex # INSERE NÓ FILHO NA FRONTEIRA (SE SATISFAZ CONDIÇÕES) alreadyExplored = False # Testa se estado do nó filho foi explorado expHash = str(child.state.row) + str(child.state.col) + str( child.state.boxes) if expHash in explored: exp = explored[expHash] if (child.state.cost >= exp.cost): alreadyExplored = True # Testa se estado do nó filho está na fronteira, caso esteja # guarda o nó existente em nFront nodeFront = None if not alreadyExplored: for node in frontier: if (child.state == node.state and child.state.row == node.state.row and child.state.col == node.state.col): nodeFront = node break # Se ainda não foi explorado if not alreadyExplored: # e não está na fronteira, adiciona à fronteira if nodeFront == None: # adiciona na fronteira se a acao nao bloqueia a solucao frontier.append(child) frontier.sort( key=lambda x: (x.getFn(), x.hn) ) # Ordena a fronteira pelo f(n), usando o valor de hn como desempate treeNodesCt += 1 else: # Se já está na fronteira temos que ver se é melhor if nodeFront.getFn() > child.getFn( ): # Nó da fronteira tem custo maior que o filho frontier.remove( nodeFront ) # Remove nó da fronteira (pior e deve ser substituído) nodeFront.remove() # Retira-se da árvore frontier.append( child) # Adiciona filho que é melhor #frontier.sort(key=lambda x: x.getFn() ) # Ordena a fronteira pelo f(n), ascendente frontier.sort( key=lambda x: (x.getFn(), x.hn) ) # Ordena a fronteira pelo f(n), usando o valor de hn como desempate # treeNodesCt não é incrementado por inclui o melhor e retira o pior else: # Conta como descartado porque o filho é pior que o nó da fronteira e foi descartado frontierDiscardedNodesCt += 1 else: exploredDicardedNodesCt += 1 print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) if (solution != None): print("!!! Solução encontrada !!!") print("!!! Custo: {}".format(solution.gn)) print("!!! Profundidade: {}\n".format(solution.depth)) print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) return buildPlan(solution) else: print("### Solução NÃO encontrada ###") return None