def test_priority_queue(): """ Ensure the priority set is sorting elements correctly. """ random_elements = [i for i in range(10)] shuffle(random_elements) pq = PriorityQueue() for e in random_elements: pq.push(e) random_elements.sort() assert [e for e in pq] == random_elements assert pq.peek() == random_elements[0] output = [] while len(pq) > 0: output.append(pq.pop()) assert output == random_elements for e in random_elements: pq.push(e) assert len(pq) == 10 pq.update_cost_limit(5) assert len(pq) == 6 output = [] while len(pq) > 0: output.append(pq.pop()) assert output == random_elements[:6] pq = PriorityQueue(node_value=lambda x: x, max_length=3) pq.push(6) pq.push(0) pq.push(2) pq.push(6) pq.push(7) assert len(pq) == 3 assert list(pq) == [0, 2, 6] pq.update_cost_limit(5) assert len(pq) == 2 assert pq.peek() == 0 assert pq.peek_value() == 0 assert pq.pop() == 0 assert pq.peek() == 2 assert pq.peek_value() == 2 assert pq.pop() == 2 assert len(pq) == 0
def local_beam_search(problem, beam_width=1, max_sideways=0, graph_search=True, cost_limit=float('-inf')): """ A variant of :func:`py_search.informed_search.beam_search` that can be applied to local search problems. When the beam width of 1 this approach yields behavior similar to :func:`hill_climbing`. :param problem: The problem to solve. :type problem: :class:`py_search.base.Problem` :param beam_width: The size of the search beam. :type beam_width: int :param max_sideways: Specifies the max number of contiguous sideways moves. :type max_sideways: int :param graph_search: Whether to use graph search (no duplicates) or tree search (duplicates) :type graph_search: Boolean """ b = None bv = float('inf') sideways_moves = 0 fringe = PriorityQueue(node_value=problem.node_value) fringe.push(problem.initial) while len(fringe) < beam_width: fringe.push(problem.random_node()) if graph_search: closed = set() closed.add(problem.initial) while len(fringe) > 0 and sideways_moves <= max_sideways: pv = fringe.peek_value() if pv > bv: yield b if pv == bv: sideways_moves += 1 else: sideways_moves = 0 parents = [] while len(fringe) > 0 and len(parents) < beam_width: parent = fringe.pop() parents.append(parent) fringe.clear() b = parents[0] bv = pv for node in parents: for s in problem.successors(node): added = True if not graph_search: fringe.push(s) elif s not in closed: fringe.push(s) closed.add(s) else: added = False if added and fringe.peek_value() <= cost_limit: yield fringe.peek() yield b