/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.hawaii.jmotif.sampler;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import edu.hawaii.jmotif.sampler.Statistics.StatisticsBuilder;
import edu.hawaii.jmotif.text.SAXCollectionStrategy;
/**
* Function decorator (Decorator pattern)
* implementing:
*
* <li>gathering statistics about function invocations</li>
* <li>providing analytical gradient/hessian detection</li>
* <li>returning analytical or numerical gradient/hessian or
* NullObject gradient/hessian</li>
*
* (Strategy pattern) Numerical gradient/hessian calculation strategy
*
* @author ytoh
*/
public class BaseObjectiveFunction implements ObjectiveFunction {
protected Function function = null;
private FunctionGradient gradient = null;
private FunctionHessian hessian = null;
private boolean hasAnalyticalGradient = false;
private boolean hasAnalyticalHessian = false;
private NumericalGradient numericalGradient = null;
private NumericalHessian numericalHessian = null;
private StatisticsBuilder statistics = null;
protected FunctionBounds bounds = null;
private boolean isFunctionBound = false;
private FunctionDynamics dynamics = null;
private boolean isFunctionDynamic = false;
/**
* Constructs an <code>ObjectiveFunction</code> able of analyzing the supplied
* function, gathering statistics and calculating numerical gradient/hessian
* after a certain strategy.
*
* @param function to analyze and wrap
*/
public BaseObjectiveFunction(Function function) {
this.function = function;
this.statistics = Statistics.newInstance();
if (function instanceof FunctionGradient) {
hasAnalyticalGradient = true;
gradient = (FunctionGradient) function;
}
if (function instanceof FunctionHessian) {
hasAnalyticalHessian = true;
hessian = (FunctionHessian) function;
}
if(function instanceof FunctionBounds) {
bounds = (FunctionBounds) function;
isFunctionBound = true;
}
if(function instanceof FunctionDynamics) {
dynamics = (FunctionDynamics) function;
isFunctionDynamic = true;
}
}
/**
* Set the prefered gradient calculation strategy if no analytical gradient
* is provided.
*
* @param numericalGradient gradient calculation strategy
*/
public void setNumericalGradient(NumericalGradient numericalGradient) {
this.numericalGradient = numericalGradient;
}
/**
* Set the prefered hessian calculation strategy if no analytical hessian
* is provided.
*
* @param numericalHessian hessian calculation strategy
*/
public void setNumericalHessian(NumericalHessian numericalHessian) {
this.numericalHessian = numericalHessian;
}
public boolean hasAnalyticalGradient() {
return hasAnalyticalGradient;
}
public boolean hasAnalyticalHessian() {
return hasAnalyticalHessian;
}
public boolean isDynamic() {
return isFunctionDynamic;
}
public boolean inBounds(Point point) throws ArrayIndexOutOfBoundsException{
if (isFunctionBound){
double[] positions = point.toArray();
double[] minima = bounds.getMinimum();
double[] maxima = bounds.getMaximum();
for (int i = 0; i < function.getDimension(); i++){
if ( positions[i] < minima[i] || positions[i] > maxima[i]){
return false;
}
}
}
return true;
}
public double valueAt(Point point) {
// count invocations
statistics.incrementValueAt();
return function.valueAt(point);
}
public int getDimension() {
return function.getDimension();
}
public Gradient gradientAt(Point point) {
// count invocations
statistics.incrementGradientAt();
if (hasAnalyticalGradient) {
return gradient.gradientAt(point);
}
// return calculated gradient according to certain strategy
if(numericalGradient != null) {
return numericalGradient.gradientAt(this, point);
}
throw new OptimizationException("Cannot compute gradient - no analytical/numerical gradient available");
}
public Hessian hessianAt(Point point) {
// count invocations
statistics.incrementHessianAt();
if (hasAnalyticalHessian) {
return hessian.hessianAt(point);
}
// return calculated hessian according to certain strategy
if(numericalHessian != null) {
return numericalHessian.hessianAt(this, point);
}
throw new OptimizationException("Cannot compute hessian - no analytical/numerical hessian available");
}
/**
* Retrieve a snapshot of the current function invocation statistics represented
* as an immutable {@link Statistics} instance.
*
* <p>The returned <code>Statistics</code> instance can be queried about
* the number of <code>valueAt</code>, <code>gradientAt</code> and <code>hessianAt</code>
* invocations.</p>
*
* @return invocation count statistics
*/
public Statistics getStatistics() {
return statistics.build();
}
public double[] getMinimum() {
if(isFunctionBound) {
return bounds.getMinimum();
}
double[] minimum = new double[function.getDimension()];
Arrays.fill(minimum, -Double.MAX_VALUE);
return minimum;
}
public double[] getMaximum() {
if(isFunctionBound) {
return bounds.getMaximum();
}
double[] maximum = new double[function.getDimension()];
Arrays.fill(maximum, Double.MAX_VALUE);
return maximum;
}
public void resetGenerationCount() {
if (isFunctionDynamic){
dynamics.resetGenerationCount();
}
}
public void nextGeneration() {
if (isFunctionDynamic){
dynamics.nextGeneration();
}
}
public void setGeneration(int currentGeneration) {
if (isFunctionDynamic){
dynamics.setGeneration(currentGeneration);
}
}
@Override
public SAXCollectionStrategy getSAXSamplingStrategy() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setUpperBounds(double[] parametersHighest) {
// TODO Auto-generated method stub
}
@Override
public void setLowerBounds(double[] parametersLowest) {
// TODO Auto-generated method stub
}
@Override
public void setStrategy(SAXCollectionStrategy noreduction) {
// TODO Auto-generated method stub
}
@Override
public void setData(Map<String, List<double[]>> trainData, int i) {
// TODO Auto-generated method stub
}
}