'Given an observation, runs the q_network to choose the current action.
Does not backprop.
Args:
observation: A one-hot encoding of a single observation (note).
exploration_period: The total length of the period the network will
spend exploring, as set in the train function.
enable_random: If False, the network cannot act randomly.
sample_next_obs: If True, the next observation will be sampled from
the softmax probabilities produced by the model, and passed back
along with the action. If False, only the action is passed back.
Returns:
The action chosen, the reward_scores returned by the reward_rnn, and the
next observation. If sample_next_obs is False, the next observation is
equal to the action.'

def action(self, observation, exploration_period=0, enable_random=True, sample_next_obs=False):

    assert (len(observation.shape) == 1), 'Single    observation    only'
    self.actions_executed_so_far += 1
    if (self.exploration_mode == 'egreedy'):
        exploration_p = rl_tuner_ops.linear_annealing(self.actions_executed_so_far, exploration_period, 1.0, self.dqn_hparams.random_action_probability)
    elif (self.exploration_mode == 'boltzmann'):
        enable_random = False
        sample_next_obs = True
    input_batch = np.reshape(observation, (self.q_network.batch_size, 1, self.input_size))
    lengths = np.full(self.q_network.batch_size, 1, dtype=int)
    (action, action_softmax, self.q_network.state_value, reward_scores, self.reward_rnn.state_value) = self.session.run([self.predicted_actions, self.action_softmax, self.q_network.state_tensor, self.reward_scores, self.reward_rnn.state_tensor], {self.q_network.melody_sequence: input_batch, self.q_network.initial_state: self.q_network.state_value, self.q_network.lengths: lengths, self.reward_rnn.melody_sequence: input_batch, self.reward_rnn.initial_state: self.reward_rnn.state_value, self.reward_rnn.lengths: lengths})
    reward_scores = np.reshape(reward_scores, self.num_actions)
    action_softmax = np.reshape(action_softmax, self.num_actions)
    action = np.reshape(action, self.num_actions)
    if (enable_random and (random.random() < exploration_p)):
        note = self.get_random_note()
        return (note, note, reward_scores)
    elif (not sample_next_obs):
        return (action, action, reward_scores)
    else:
        obs_note = rl_tuner_ops.sample_softmax(action_softmax)
        next_obs = np.array(rl_tuner_ops.make_onehot([obs_note], self.num_actions)).flatten()
        return (action, next_obs, reward_scores)
