/* * 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 java.util.Arrays; /** * Implements a Hopfield network. * */ public class HopfieldNetwork extends EnergeticNetwork { /** * Serial id. */ private static final long serialVersionUID = 1L; /** * Default constructor. */ public HopfieldNetwork() { } /** * Construct a Hopfield with the specified neuron count. * @param neuronCount The neuron count. */ public HopfieldNetwork(final int neuronCount) { super(neuronCount); } /** * Note: for Hopfield networks, you will usually want to call the "run" * method to compute the output. * * This method can be used to copy the input data to the current state. A * single iteration is then run, and the new current state is returned. * * @param input * The input pattern. * @return The new current state. */ public double[] compute(final double[] input) { final double[] result = new double[input.length]; System.arraycopy(input, 0, getCurrentState(), 0, input.length); run(); for (int i = 0; i < getCurrentState().length; i++) { result[i] = activationFunction(getCurrentState()[i]); } System.arraycopy(getCurrentState(), 0, result, 0, result.length); return result; } public double activationFunction(double d) { return (d>0)?1:0; } /** * {@inheritDoc} */ public int getInputCount() { return super.getNeuronCount(); } /** * {@inheritDoc} */ public int getOutputCount() { return super.getNeuronCount(); } /** * Perform one Hopfield iteration. */ public void run() { for (int toNeuron = 0; toNeuron < getNeuronCount(); toNeuron++) { double sum = 0; for (int fromNeuron = 0; fromNeuron < getNeuronCount(); fromNeuron++) { sum += getCurrentState()[fromNeuron] * getWeight(fromNeuron, toNeuron); } getCurrentState()[toNeuron] = activationFunction(sum); } } /** * Run the network until it becomes stable and does not change from more * runs. * * @param max * The maximum number of cycles to run before giving up. * @return The number of cycles that were run. */ public int runUntilStable(final int max) { boolean done = false; String lastStateStr = Arrays.toString(getCurrentState()); String currentStateStr = lastStateStr; int cycle = 0; do { run(); cycle++; lastStateStr = Arrays.toString(getCurrentState()); if (!currentStateStr.equals(lastStateStr)) { if (cycle > max) { done = true; } } else { done = true; } currentStateStr = lastStateStr; } while (!done); return cycle; } /** * Calculate the energy for this network. * @return The energy. */ public double energy() { double t = 0; // Calculate first term double a = 0; for(int i=0;i<this.getInputCount();i++) { for(int j=0;j<this.getOutputCount();j++) { a+=this.getWeight(i,j) * this.getCurrentState()[i] * this.getCurrentState()[j]; } } a*=-0.5; // Calculate second term double b = 0; for(int i=0;i<this.getInputCount();i++) { b+=this.getCurrentState()[i] * t; } return a+b; } }