// Catalano Machine Learning Library
// The Catalano Framework
//
// Copyright © Diego Catalano, 2012-2016
// diego.catalano at live.com
//
// Copyright © Andrew Kirillov, 2007-2008
// andrew.kirillov@gmail.com
//
//    This library is free software; you can redistribute it and/or
//    modify it under the terms of the GNU Lesser General Public
//    License as published by the Free Software Foundation; either
//    version 2.1 of the License, or (at your option) any later version.
//
//    This library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//    Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public
//    License along with this library; if not, write to the Free Software
//    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//

package Catalano.MachineLearning.Exploration;

import java.util.Random;

/**
 * The class provides implementation of Sarse algorithm, known as on-policy Temporal Difference control.
 * @author Diego Catalano
 */
public class Sarsa {
    // amount of possible states
    private int states;
    // amount of possible actions
    private int actions;
    // q-values
    private double[][] qvalues;
    // exploration policy
    private IExplorationPolicy explorationPolicy;

    // discount factor
    private double discountFactor = 0.95;
    // learning rate
    private double learningRate = 0.25;

    /**
     * Amount of possible states.
     * @return States
     */
    public int getStates() {
        return states;
    }

    /**
     * Amount of possible actions.
     * @return Actions
     */
    public int getActions() {
        return actions;
    }

    /**
     * Exploration policy.
     * @return Exploration policy.
     */
    public IExplorationPolicy getExplorationPolicy() {
        return explorationPolicy;
    }

    /**
     * Exploration policy.
     * Policy, which is used to select actions.
     * @param explorationPolicy Exploration policy
     */
    public void setExplorationPolicy(IExplorationPolicy explorationPolicy) {
        this.explorationPolicy = explorationPolicy;
    }

    /**
     * Get learning rate
     * @return Learning rate
     */
    public double getLearningRate() {
        return learningRate;
    }

    /**
     * Learning rate, [0, 1].
     * The value determines the amount of updates Q-function receives
     * during learning. The greater the value, the more updates the function receives.
     * The lower the value, the less updates it receives.
     * @param learningRate Learning rate
     */
    public void setLearningRate(double learningRate) {
        this.learningRate = Math.max(0.0, Math.min(1.0, learningRate));
    }

    /**
     * Get Discount Factor
     * @return Discount Factor
     */
    public double getDiscountFactor() {
        return discountFactor;
    }

    /**
     * Discount factor, [0, 1].
     * Discount factor for the expected summary reward. The value serves as
     * multiplier for the expected reward. So if the value is set to 1,
     * then the expected summary reward is not discounted. If the value is getting
     * smaller, then smaller amount of the expected reward is used for actions'
     * estimates update.
     * @param discountFactor Discount Factor
     */
    public void setDiscountFactor(double discountFactor) {
        this.discountFactor = Math.max(0.0, Math.min(1.0, discountFactor));
    }
    
    /**
     * Initializes a new instance of the Sarsa class.
     * @param states Amount of possible states.
     * @param actions Amount of possible actions.
     * @param explorationPolicy Exploration policy.
     * @param randomize Randomize action estimates or not.
     * 
     * The randomize parameter specifies if initial action estimates should be randomized
     * with small values or not. Randomization of action values may be useful, when greedy exploration
     * policies are used. In this case randomization ensures that actions of the same type are not chosen always.
     */
    public Sarsa( int states, int actions, IExplorationPolicy explorationPolicy, boolean randomize ){
        this.states = states;
        this.actions = actions;
        this.explorationPolicy = explorationPolicy;

        // create Q-array
        qvalues = new double[states][];
        for ( int i = 0; i < states; i++ ){
            qvalues[i] = new double[actions];
        }

        // do randomization
        if ( randomize ){
            Random r = new Random( );

            for ( int i = 0; i < states; i++ ){
                for ( int j = 0; j < actions; j++ ){
                    qvalues[i][j] = r.nextDouble() / 10;
                }
            }
        }
    }
    
    /**
     * Get next action from the specified state.
     * @param state Current state to get an action for.
     * @return Returns the action for the state.
     */
    public int GetAction( int state ){
        return explorationPolicy.ChooseAction( qvalues[state] );
    }
    
    /**
     * Update Q-function's value for the previous state-action pair.
     * @param previousState Current state.
     * @param previousAction Action, which lead from previous to the next state.
     * @param reward Reward value, received by taking specified action from previous state.
     * @param nextState Next state.
     * @param nextAction Next action.
     */
    public void UpdateState( int previousState, int previousAction, double reward, int nextState, int nextAction ){
        // previous state's action estimations
        double[] previousActionEstimations = qvalues[previousState];
        // update expexted summary reward of the previous state
        previousActionEstimations[previousAction] *= ( 1.0 - learningRate );
        previousActionEstimations[previousAction] += ( learningRate * ( reward + discountFactor * 
                                                        qvalues[nextState][nextAction] ) );

    }
    
    /**
     * Update Q-function's value for the previous state-action pair.
     * @param previousState Current state.
     * @param previousAction Action, which lead from previous to the next state.
     * @param reward Reward value, received by taking specified action from previous state.
     * 
     * Updates Q-function's value for the previous state-action pair in
     * the case if the next state is terminal.
     */
    public void UpdateState( int previousState, int previousAction, double reward ){
        // previous state's action estimations
        double[] previousActionEstimations = qvalues[previousState];
        // update expexted summary reward of the previous state
        previousActionEstimations[previousAction] *= ( 1.0 - learningRate );
        previousActionEstimations[previousAction] += ( learningRate * reward );
    }
    
}

 

Ads help maintain this website.