//  [python]
def softmax_label_sample(labels, predicted_scores):
	permutation_loss = loss_fns.get_listnet_loss(labels, predicted_scores)

	predicted_scores = tf.reshape(predicted_scores, [-1, 1])
	labels = tf.reshape(labels, [-1, 1])
	n_data = tf.shape(labels)[0]
	# # [[1. 0. 0.]]
	transposed_labels = tf.transpose(labels)
	exps = tf.exp(transposed_labels)
	# # keep it substruct 
	exp_sum = tf.reduce_sum(exps)
	# # [[0.5761169  0.21194157 0.21194157]]
	softmax_scores = tf.truediv(exps, exp_sum)
	# # [[1]]
	action_0_index = tf.multinomial(softmax_scores, 1)
	action_0_index = tf.cast(action_0_index, tf.int32)
	# predicted_scores has been vertical
	action_0 = tf.gather(predicted_scores, tf.reshape(action_0_index, [-1, 1]))
	action_0 = tf.reshape(action_0, [1, -1])
	actions = action_0

	label_0 = tf.gather(labels, tf.reshape(action_0_index, [-1, 1]))
	label_0 = tf.reshape(label_0, [1, -1])
	new_labels = label_0


	indices = tf.range(n_data, dtype=tf.int32)
	keep_indices = tf.where(tf.not_equal(indices, tf.squeeze(action_0_index)))
	# predicted_scores have always been vertical
	# keep_predicted_scores have always been vertical	
	keep_predicted_scores = tf.gather_nd(predicted_scores, keep_indices)
	
	keep_labels = tf.gather_nd(labels, keep_indices)
	# horizontal label
	keep_labels = tf.transpose(keep_labels)

	log_2 = tf.log(tf.constant(2.0, dtype=tf.float32))

	iteration = n_data - 1
	shape_invariants = [iteration.get_shape(), tf.TensorShape([None, 1]), 
	tf.TensorShape([None, 1]), tf.TensorShape([1, None]), tf.TensorShape([None, 1]), permutation_loss.get_shape()]

	def _cond(iteration, keep_predicted_scores, actions, keep_labels, new_labels, permutation_loss):
	    return tf.greater(iteration, 1)

	def _gen_loop_body():
	    def loop_body(iteration, keep_predicted_scores, actions, keep_labels, new_labels, permutation_loss):
	        discount = tf.log(tf.cast(tf.squeeze(n_data - iteration) + 2, dtype=tf.float32)) / log_2
	        exps = tf.exp(keep_labels)
	        # # keep it substruct 
	        exp_sum = tf.reduce_sum(exps)
	        # # [[0.5761169  0.21194157 0.21194157]]
	        softmax_scores = tf.truediv(exps, exp_sum)
	        # # [[1]]
	        action_i_index = tf.multinomial(softmax_scores, 1)
	        action_i_index = tf.cast(action_i_index, tf.int32)
	        action_i = tf.gather(keep_predicted_scores, tf.reshape(action_i_index, [-1, 1]))
	        action_i = tf.reshape(action_i, [1, -1])
	        actions = tf.concat([actions, action_i], 0)
	        # similar for labels
	        label_i = tf.gather(tf.transpose(keep_labels), tf.reshape(action_i_index, [-1, 1]))
	        label_i = tf.reshape(label_i, [1, -1])
	        new_labels = tf.concat([new_labels, label_i], 0)
	        
	        indices = tf.range(iteration, dtype=tf.int32)
	        keep_indices = tf.where(tf.not_equal(indices, tf.squeeze(action_i_index)))
	        keep_predicted_scores = tf.gather_nd(keep_predicted_scores, keep_indices)
	        
	        # labels have always been vertical
	        # keep_labels have always been vertical
	        keep_labels = tf.gather_nd(tf.transpose(keep_labels), keep_indices)
	        keep_labels = tf.transpose(keep_labels) 
	        
	        return tf.subtract(iteration, 1), keep_predicted_scores, actions, keep_labels, new_labels, permutation_loss
	    return loop_body

	iteration, keep_predicted_scores, actions, keep_labels, new_labels, permutation_loss = tf.while_loop(_cond, _gen_loop_body(),
	[iteration, keep_predicted_scores, actions, keep_labels, new_labels, permutation_loss], shape_invariants=shape_invariants)	
	# the final action
	actions = tf.concat([actions, keep_predicted_scores], 0)
	new_labels = tf.concat([new_labels, keep_labels], 0)
	new_labels = tf.reshape(new_labels, [-1, 1])
	actions = tf.reshape(actions, [-1, 1])	
	return 	new_labels, actions, permutation_loss