/*
* Artificial Intelligence for Humans
* Volume 3: Deep Learning and Neural Networks
* Java Version
* http://www.aifh.org
* http://www.jeffheaton.com
*
* Code repository:
* https://github.com/jeffheaton/aifh
*
* Copyright 2014-2015 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.energetic;
import com.heatonresearch.aifh.AIFHError;
import com.heatonresearch.aifh.learning.MLMethod;
import com.heatonresearch.aifh.randomize.GenerateRandom;
/**
* The energetic network forms the base class for Hopfield and Boltzmann machines.
* @author jheaton
*
*/
public abstract class EnergeticNetwork implements MLMethod {
/**
* Serial id.
*/
private static final long serialVersionUID = 1L;
/**
* The current state of the thermal network.
*/
private double[] currentState;
/**
* The weights.
*/
private double[] weights;
/**
* The neuron count.
*/
private int neuronCount;
/**
* Default constructor.
*/
public EnergeticNetwork() {
}
/**
* Construct the network with the specified neuron count.
* @param neuronCount The number of neurons.
*/
public EnergeticNetwork(final int neuronCount) {
this.neuronCount = neuronCount;
this.weights = new double[neuronCount * neuronCount];
this.currentState = new double[neuronCount];
}
/**
* Add to the specified weight.
* @param fromNeuron The from neuron.
* @param toNeuron The to neuron.
* @param value The value to add.
*/
public void addWeight(final int fromNeuron, final int toNeuron,
final double value) {
final int index = (toNeuron * this.neuronCount) + fromNeuron;
if (index >= this.weights.length) {
throw new AIFHError("Out of range: fromNeuron:"
+ fromNeuron + ", toNeuron: " + toNeuron);
}
this.weights[index] += value;
}
/**
* @return Calculate the current energy for the network. The network will
* seek to lower this value.
*/
public double calculateEnergy() {
double tempE = 0;
final int neuronCount = getNeuronCount();
for (int i = 0; i < neuronCount; i++) {
for (int j = 0; j < neuronCount; j++) {
if (i != j) {
tempE += getWeight(i, j) * this.currentState[i]
* this.currentState[j];
}
}
}
return -1 * tempE / 2;
}
/**
* Clear any connection weights.
*/
public void clear() {
for(int i=0;i<this.weights.length;i++) {
this.weights[i] = 0;
}
}
/**
* @return The current state of the network.
*/
public double[] getCurrentState() {
return this.currentState;
}
/**
* @return Get the neuron count for the network.
*/
public int getNeuronCount() {
return this.neuronCount;
}
/**
* Get a weight.
* @param fromNeuron The from neuron.
* @param toNeuron The to neuron.
* @return The weight.
*/
public double getWeight(final int fromNeuron, final int toNeuron) {
final int index = (toNeuron * this.neuronCount) + fromNeuron;
return this.weights[index];
}
/**
* @return The weights.
*/
public double[] getWeights() {
return this.weights;
}
/**
* Init the network.
* @param neuronCount The neuron count.
* @param weights The weights.
* @param output The output.
*/
public void init(final int neuronCount, final double[] weights,
final double[] output) {
if (neuronCount != output.length) {
throw new AIFHError("Neuron count(" + neuronCount
+ ") must match output count(" + output.length + ").");
}
if ((neuronCount * neuronCount) != weights.length) {
throw new AIFHError("Weight count(" + weights.length
+ ") must be the square of the neuron count(" + neuronCount
+ ").");
}
this.neuronCount = neuronCount;
this.weights = weights;
this.currentState = new double[neuronCount];
System.arraycopy(output, 0, this.currentState, 0, this.currentState.length);
}
/**
* Randomize the weights.
* @param rand The random number generator to use.
*/
public void reset(final GenerateRandom rand) {
for(int i=0;i<this.currentState.length;i++) {
this.currentState[i] = 0;
}
for(int i=0;i<this.weights.length;i++) {
this.weights[i] = 0;
}
}
/**
* Set the current state.
* @param s The current state array.
*/
public void setCurrentState(final double[] s) {
this.currentState = new double[s.length];
System.arraycopy(s, 0, this.currentState, 0, s.length);
}
/**
* Set the neuron count.
* @param c The neuron count.
*/
public void setNeuronCount(final int c) {
this.neuronCount = c;
}
/**
* Set the weight.
* @param fromNeuron The from neuron.
* @param toNeuron The to neuron.
* @param value The value.
*/
public void setWeight(final int fromNeuron, final int toNeuron,
final double value) {
final int index = (toNeuron * this.neuronCount) + fromNeuron;
this.weights[index] = value;
}
/**
* Set the weight array.
* @param w The weight array.
*/
public void setWeights(final double[] w) {
this.weights = w;
}
@Override
public double[] getLongTermMemory() {
return this.weights;
}
}