/*
* Artificial Intelligence for Humans
* Volume 1: Fundamental Algorithms
* Java Version
* http://www.aifh.org
* http://www.jeffheaton.com
*
* Code repository:
* https://github.com/jeffheaton/aifh
* Copyright 2013 by Jeff Heaton
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package com.heatonresearch.aifh.learning;
import com.heatonresearch.aifh.learning.score.ScoreFunction;
/**
* Train using hill climbing. Hill climbing can be used to optimize the long term memory of a Machine Learning
* Algorithm. This is done by moving the current long term memory values to a new location if that new location
* gives a better score from the scoring function.
* <p/>
* http://en.wikipedia.org/wiki/Hill_climbing
*/
public class TrainHillClimb implements LearningMethod {
/**
* The machine learning algorithm to optimize.
*/
private final MachineLearningAlgorithm algorithm;
/**
* The last result from the score function.
*/
private double lastError;
/**
* The score function.
*/
private final ScoreFunction score;
/**
* The candidate moves.
*/
private final double[] candidate = new double[5];
/**
* The current step size.
*/
private final double[] stepSize;
/**
* True, if we want to minimize the score function.
*/
private final boolean shouldMinimize;
/**
* Construct a hill climbing algorithm.
*
* @param theShouldMinimize True, if we should minimize.
* @param theAlgorithm The algorithm to optimize.
* @param theScore The scoring function.
* @param acceleration The acceleration for step sizes.
* @param stepSize The initial step sizes.
*/
public TrainHillClimb(final boolean theShouldMinimize, final MachineLearningAlgorithm theAlgorithm, final ScoreFunction theScore,
final double acceleration, final double stepSize) {
this.algorithm = theAlgorithm;
this.score = theScore;
this.shouldMinimize = theShouldMinimize;
this.stepSize = new double[theAlgorithm.getLongTermMemory().length];
for (int i = 0; i < theAlgorithm.getLongTermMemory().length; i++) {
this.stepSize[i] = stepSize;
}
candidate[0] = -acceleration;
candidate[1] = -1 / acceleration;
candidate[2] = 0;
candidate[3] = 1 / acceleration;
candidate[4] = acceleration;
// Set the last error to a really bad value so it will be reset on the first iteration.
if (this.shouldMinimize) {
this.lastError = Double.POSITIVE_INFINITY;
} else {
this.lastError = Double.NEGATIVE_INFINITY;
}
}
/**
* Construct a hill climbing algorithm. Use acceleration of 1.2 and initial step size of 1.
*
* @param theShouldMinimize True, if we should minimize.
* @param theAlgorithm The algorithm to optimize.
* @param theScore The scoring function.
*/
public TrainHillClimb(final boolean theShouldMinimize, final MachineLearningAlgorithm theAlgorithm, final ScoreFunction theScore) {
this(theShouldMinimize, theAlgorithm, theScore, 1.2, 1);
}
/**
* {@inheritDoc}
*/
@Override
public void iteration() {
final int len = this.algorithm.getLongTermMemory().length;
for (int i = 0; i < len; i++) {
int best = -1;
double bestScore = this.shouldMinimize ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
for (int j = 0; j < candidate.length; j++) {
this.algorithm.getLongTermMemory()[i] += stepSize[i] * candidate[j];
final double temp = score.calculateScore(this.algorithm);
this.algorithm.getLongTermMemory()[i] -= stepSize[i] * candidate[j];
if ((temp < bestScore) ? shouldMinimize : !shouldMinimize) {
bestScore = temp;
this.lastError = bestScore;
best = j;
}
}
if (best != -1) {
this.algorithm.getLongTermMemory()[i] += stepSize[i] * candidate[best];
stepSize[i] = stepSize[i] * candidate[best];
}
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean done() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public double getLastError() {
return this.lastError;
}
/**
* {@inheritDoc}
*/
public String getStatus() {
return "";
}
/**
* {@inheritDoc}
*/
@Override
public void finishTraining() {
}
}