/*
* File name: ActivationFunction.java (package eas.simulation.brain.neural)
* Author(s): Lukas König
* Java version: 6.0
* Generation date: 29.07.2011 (09:59:31)
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
* author or licensor (but not in any way that suggests that they endorse
* you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
* distribute the resulting work only under the same or a similar license to
* this one.
*
* + Detailed license conditions (Germany):
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/
package eas.simulation.brain.neural.functions;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import eas.miscellaneous.StaticMethods;
/**
* Interface modeling the activation function Phi: R => R of a neuron.
* Do not confuse with TransferFunction which models the computation of
* the weighted input of a neuron. (In literature the term transfer function is
* often referring to the activation function as well.)
*
* IMPORTANT: Activation functions are constrained to return values from [0, 1].
*
* @author Lukas König
*/
public abstract class ActivationFunction implements Serializable {
/**
*
*/
private static final long serialVersionUID = -276624979093194153L;
private double xMin;
private double xMax;
private boolean paintBlueBorder = true;
public void setPaintBlueBorder(boolean paintBlueBorder) {
this.paintBlueBorder = paintBlueBorder;
}
public ActivationFunction() {
this(-4, 4);
}
public ActivationFunction(
final double fctXMin,
final double fctXMax) {
this.xMin = fctXMin;
this.xMax = fctXMax;
// TEST:
// double r = new Random().nextDouble() * 100;
// double diff = 0;
// try {
// diff = Math.abs(this.activationPhi(this.inverseActivationPhi(r)) - r);
// } catch (InversionNotSupportedException e) {}
//
// if (diff > 0.01) {
// GlobalVariables.getPrematureParameters().logWarning(this.getClass().getSimpleName() + ": Activation of Inverse Activation not equal to original value " + r + " (diff: " + diff + ")");
// }
}
/**
* Computes the activation function.
*
* IMPORTANT: Activation functions are constrained to return values from
* [0, 1].
*
* @param input The net input of the neuron.
*
* @return The net output of the neuron.
*/
public abstract double activationPhi(double input);
/**
* Computes the inverse of the activation function. If the activation
* function is irreversible, an InversionNotSupported should be thrown.
*
* @param output The given output of the neuron.
*
* @return The net input of the neuron.
* @throws InversionNotSupportedException
*/
public abstract double inverseActivationPhi(double output) throws InversionNotSupportedException;
public BufferedImage getFunctionView(int width, int height) {
BufferedImage img
= new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
Double[] values = new Double[width];
double x = this.xMin;
double step = (xMax - xMin) / width;
double yMin = Double.POSITIVE_INFINITY;
double yMax = Double.NEGATIVE_INFINITY;
for (int i = 0; i < values.length; i++) {
values[i] = this.activationPhi(x);
if (values[i] > yMax) {
yMax = values[i];
}
if (values[i] < yMin) {
yMin = values[i];
}
x += step;
}
g.setColor(Color.white);
g.fillRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
g.setColor(Color.blue);
if (width < VERY_SMALL_PIC || height < VERY_SMALL_PIC) {
values = StaticMethods.normalize(values, yMin, yMax, 3.0, (double) height - 4);
g.setStroke(new BasicStroke(1));
for (int i = 1; i < values.length; i++) {
g.drawLine(i - 1, height - 1 - values[i - 1].intValue(), i,
height - 1 - values[i].intValue());
}
} else {
g.drawImage(
this.getChart(values, xMin, step, width, height),
0,
0,
null);
}
if (this.paintBlueBorder) {
g.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
}
return img;
}
private final static int SMALL_PIC = 100;
private final static int VERY_SMALL_PIC = 50;
private BufferedImage getChart(Double[] values, double xMin, double step, int width, int height) {
XYSeries series = new XYSeries("series1");
double x = xMin;
for (int i = 0; i < values.length; i++) {
series.add(x, values[i]);
x += step;
}
XYSeriesCollection serieses = new XYSeriesCollection(series);
NumberAxis domain = new NumberAxis();
NumberAxis range = new NumberAxis();
if (width < SMALL_PIC || height < SMALL_PIC) {
domain.setTickLabelsVisible(false);
range.setTickLabelsVisible(false);
}
XYPlot plot = new XYPlot(serieses, domain, range, new XYLineAndShapeRenderer(true, false));
JFreeChart chart = new JFreeChart(plot);
chart.removeLegend();
if (width < SMALL_PIC || height < SMALL_PIC) {
} else {
chart.setTitle(new TextTitle(this.toString(), new Font("Arial", 0, 12)));
}
return chart.createBufferedImage(width, height);
}
@Override
public abstract String toString();
@Override
public abstract boolean equals(Object obj);
@Override
public abstract int hashCode();
}