'Performs beam search for decoding.
Args:
sess: tf.Session, session
enc_inputs: ndarray of shape (enc_length, 1), the document ids to encode
enc_seqlen: ndarray of shape (1), the length of the sequnce
Returns:
hyps: list of Hypothesis, the best hypotheses found by beam search,
ordered by score'

def BeamSearch(self, sess, enc_inputs, enc_seqlen):

    (enc_top_states, dec_in_state) = self._model.encode_top_state(sess, enc_inputs, enc_seqlen)
    hyps = ([Hypothesis([self._start_token], 0.0, dec_in_state)] * self._beam_size)
    results = []
    steps = 0
    while ((steps < self._max_steps) and (len(results) < self._beam_size)):
        latest_tokens = [h.latest_token for h in hyps]
        states = [h.state for h in hyps]
        (topk_ids, topk_log_probs, new_states) = self._model.decode_topk(sess, latest_tokens, enc_top_states, states)
        all_hyps = []
        num_beam_source = (1 if (steps == 0) else len(hyps))
        for i in xrange(num_beam_source):
            (h, ns) = (hyps[i], new_states[i])
            for j in xrange((self._beam_size * 2)):
                all_hyps.append(h.Extend(topk_ids[(i, j)], topk_log_probs[(i, j)], ns))
        hyps = []
        for h in self._BestHyps(all_hyps):
            if (h.latest_token == self._end_token):
                results.append(h)
            else:
                hyps.append(h)
            if ((len(hyps) == self._beam_size) or (len(results) == self._beam_size)):
                break
        steps += 1
    if (steps == self._max_steps):
        results.extend(hyps)
    return self._BestHyps(results)
