'Generate samples for the batch from the NADE.
Args:
b_enc: External encoder bias terms (`b` in [1]), sized
`[batch_size, num_hidden]`.
b_dec: External decoder bias terms (`c` in [1]), sized
`[batch_size, num_dims]`.
Returns:
sample: The generated samples, sized `[batch_size, num_dims]`.
log_prob: The log probabilities of each observation in the batch, sized
`[batch_size, 1]`.'

def sample(self, b_enc, b_dec):

    batch_size = tf.shape(b_enc)[0]
    a_0 = b_enc
    sample_0 = []
    log_p_0 = tf.zeros([batch_size, 1])
    w_enc_arr = tf.unstack(self.w_enc)
    w_dec_arr = tf.unstack(self.w_dec_t)
    b_dec_arr = tf.unstack(tf.reshape(tf.transpose(b_dec), [self.num_dims, batch_size, 1]))
    def loop_body(i, a, sample, log_p):
        'Accumulate    hidden    state,    sample,    and    log    probability    for    index    i.'
        w_enc_i = w_enc_arr[i]
        w_dec_i = w_dec_arr[i]
        b_dec_i = b_dec_arr[i]
        cond_p_i = self._cond_prob(a, w_dec_i, b_dec_i)
        bernoulli = tf.contrib.distributions.Bernoulli(probs=cond_p_i, dtype=tf.float32)
        v_i = bernoulli.sample()
        sample_new = (sample + [v_i])
        log_p_i = ((v_i * safe_log(cond_p_i)) + ((1 - v_i) * safe_log((1 - cond_p_i))))
        log_p_new = (log_p + log_p_i)
        a_new = (a + tf.matmul(v_i, w_enc_i))
        return (a_new, sample_new, log_p_new)
    (a, sample, log_p) = (a_0, sample_0, log_p_0)
    for i in range(self.num_dims):
        (a, sample, log_p) = loop_body(i, a, sample, log_p)
    return (tf.transpose(tf.squeeze(tf.stack(sample), [2])), log_p)
