using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BCMToolbox { #region Hebbian2 Base public abstract class SynchronousHebbian2Network : FixedTraceableNetwork { double[] __intermediaryOutputs = null; protected Func __activation = MathToolbox.Sigmoid; protected Func __activation_inverse = MathToolbox.InverseSigmoid; public SynchronousHebbian2Network(int neuronCount, int newID) : base(neuronCount, newID) { __intermediaryOutputs = new double[neuronCount]; } public override string Identification { get { return String.Format("Hebb2 Layer #{0}", this.UID); } } public virtual double Inertia { get { return 0.02; } } public virtual double OutputDecay { get { return 0.85; } } protected abstract double WeightModificationKernel(double weight, double input, double output); public virtual bool HasNormalizedWeights { get { return false; } } public virtual bool HasNormalizedInputs { get { return false; } } public override void ApplyInputs(double[] inputs) { lock (SyncRoot) { if (inputs == null) throw new ArgumentNullException(); if (inputs.Length != this.Count) throw new ArgumentException("Invalid input size. Expected: ", this.Count.ToString()); for (int i = 0; i < this.Count; i++) __potentials[i] += inputs[i]; } if(HasNormalizedInputs) NormalizePotentials(2.0); base.ApplyInputs(inputs); } public override void Propagate() { // calculate outputs for (int i = 0; i < this.Count; i++) { __intermediaryOutputs[i] = 0.0; for (int j = 0; j < this.Count; j++) if ((i != j) && !double.IsNaN(__weights[j, i])) __intermediaryOutputs[i] += __weights[j, i] * __potentials[j]; __intermediaryOutputs[i] = __activation(__intermediaryOutputs[i]); } if (HasNormalizedInputs) { double[] temp = __potentials; __potentials = __intermediaryOutputs; NormalizePotentials(2.0); __potentials = temp; } // update weights and lock outputs lock (SyncRoot) { for (int i = 0; i < this.Count; i++) for (int j = 0; j < this.Count; j++) { if ((i == j) || double.IsNaN(__weights[i, j])) continue; __weights[i,j] = WeightModificationKernel(__weights[i, j], __potentials[i], __intermediaryOutputs[j]); System.Diagnostics.Debug.Assert(!double.IsNaN(__weights[i, j])); System.Diagnostics.Debug.Assert(!double.IsInfinity(__weights[i, j])); } if(HasNormalizedWeights) NormalizeWeights(2.0); for (int i = 0; i < this.Count; i++) __potentials[i] = __intermediaryOutputs[i] * OutputDecay; } base.Propagate(); } public override void Initialize(Func initializerWeights, Func initializerPotentials) { base.Initialize(initializerWeights, initializerPotentials); if(HasNormalizedInputs) NormalizePotentials(2.0); if (HasNormalizedWeights) NormalizeWeights(2.0); } } #endregion // 0->0 (--), 1->0 (+), 1->1 (++), 0->1 (-) #region Model 01 public class Model01 : SynchronousHebbian2Network { const double EXC_THRESHOLD = 0.5; const double MEMORY_CONSTANT = 2.5; public Model01(int neuronCount, int newID) : base(neuronCount, newID) { } protected override double WeightModificationKernel(double weight, double input, double output) { double unpacked = __activation_inverse(weight); unpacked += Math.Sign(input - EXC_THRESHOLD)*Math.Pow(Math.Abs(input - EXC_THRESHOLD), MEMORY_CONSTANT) * (1 - Math.Abs(input - output)) * Inertia; unpacked = __activation(unpacked); return unpacked; } public override double Inertia { get { return 0.02; } } } #endregion }