1 namespace SpikingNeuronNetwork.Lib.NeuronModels
5 using System.Collections.Generic;
18 public const double DefaultIo = -0.001;
23 public static double Alpha = 1;
28 public static double Offset = 0.0001;
33 public double Io {
get; set; }
35 #region Readonly Properties
40 public override double PostSpikeState
42 get {
return -Math.PI; }
48 public override double SpikeThreshold
50 get {
return Math.PI; }
56 public override double InitialState
58 get {
return (Io < 0) ? PositiveFixedPoint + Offset : 0; }
64 public override double RemainingTimeToSpike
70 return (1 / Beta) * ((SpikeThreshold / 2) - Math.Atan(C1));
72 if (State.StateVariable > PositiveFixedPoint && State.StateVariable < SpikeThreshold)
74 return (1 / Beta) * Atanh(1 / C1);
76 return Double.PositiveInfinity;
89 return OperatingRegion.TonicSpiking;
91 if (State.StateVariable < PositiveFixedPoint && State.StateVariable > -PositiveFixedPoint)
93 return OperatingRegion.Quiescent;
95 if (State.StateVariable >= PositiveFixedPoint)
97 return OperatingRegion.SpikeGeneration;
99 return OperatingRegion.Refractory;
106 public override double MaxNumericalIntegrationIterations
110 double simulationLimit;
112 if (SpikeQueue.Count > 0)
114 simulationLimit = (SpikeQueue.Last().Time + 1.5*(Io < 0 ? BaselineFiringTime : RemainingTimeToSpike));
118 simulationLimit = 1.1*BaselineFiringTime;
120 return simulationLimit;
129 get {
return Io > 0 ? SpikeThreshold/Beta : Double.NaN; }
137 get {
return Math.Sqrt(Math.Abs(Alpha*Io)); }
143 public double PositiveFixedPoint
145 get {
return (Io < 0) ? Math.Acos((1 + Alpha*Io)/(1 - Alpha*Io)) : Double.NaN; }
151 public double BaselineFiringTime
153 get {
return (1/Beta)*Atanh(Beta/Math.Tan((InitialState)/2)); }
161 get {
return Math.Tan(State.StateVariable/2)/Beta; }
171 private static double Atanh(
double x)
173 return (0.5 * Math.Log((1.0 + x) / (1.0 - x)));
191 : base(network, neuronIndex)
202 public ThetaNeuron(IReadOnlyList<double> weights,
double newIo = DefaultIo)
215 public ThetaNeuron(
int numInputs = 3,
double weightIni = 1e6,
double newIo = DefaultIo)
216 : base(numInputs, weightIni)
229 return ((1 - Math.Cos(phase)) + Alpha*Io*(1 + Math.Cos(phase)));
238 return new ThetaNeuron(Weights.Select(x => x.Value).ToList())
240 NeuronIndex = NeuronIndex,
241 NeuronNetwork = null,
254 var neuronStringBuilder =
new StringBuilder();
255 neuronStringBuilder.AppendLine(
"\nNeuron Properties: ");
256 neuronStringBuilder.AppendLine(
"\tBeta: " + String.Format(
"{0:0.0000}", Beta));
257 neuronStringBuilder.AppendLine(
"\tIo: " + Io);
258 neuronStringBuilder.AppendLine(
"\tPositive Fixed Point: " + String.Format(
"{0:0.0000}", PositiveFixedPoint));
259 neuronStringBuilder.AppendLine(
"\tPhase: " + String.Format(
"{0:0.0000}", State.StateVariable));
260 neuronStringBuilder.AppendLine(
"\tTime: " + String.Format(
"{0:0.0000}", State.Time));
261 neuronStringBuilder.AppendLine(
"\tNumber of Inputs: " + NumInputs);
262 neuronStringBuilder.AppendLine(
"\tWeights: ");
263 neuronStringBuilder.Append(
"\t\t");
264 neuronStringBuilder.AppendLine(GetWeightsString(Weights));
265 neuronStringBuilder.AppendLine();
266 neuronStringBuilder.AppendLine();
267 return neuronStringBuilder.ToString();
277 public override List<Spike>
RunThetaNeuron(List<Spike> inputSpikes,
int maxNumOutputSpikes = MaxNumOutputSpikes)
279 SpikeQueue = SpikePriorityQueue.CreateSpikeQueue(inputSpikes, State.Time);
280 var outputSpikes =
new List<Spike>();
281 if (SpikeQueue.Count == 0)
288 Console.WriteLine(
"Input Spike Times: ");
289 Console.Write(SpikeSet.GetSpikeTimesString(inputSpikes));
290 Console.WriteLine(
"Baseline Firing Time: " + BaselineFiringTime);
291 Console.WriteLine(
"Simulation Method: " + Method);
297 case SimulationMethod.EventDriven:
299 while (SpikeQueue.Count > 0)
302 var newOutputSpikeTimes = ProcessSpike(SpikeQueue.Dequeue(), out spikeStats);
303 if (newOutputSpikeTimes != null)
305 outputSpikes.AddRange(newOutputSpikeTimes);
308 if (outputSpikes.Count>=maxNumOutputSpikes)
320 if ((Io < 0 && State.StateVariable > PositiveFixedPoint) || (Io > 0 && (outputSpikes.Count == 0 || State.Time > outputSpikes.Last().Time)))
322 outputSpikes.Add(
new Spike { NeuronIndex = NeuronIndex, Time = NextSpikeTime });
325 Console.WriteLine(
"---> " + outputSpikes.Last());
331 case SimulationMethod.Numerical:
333 outputSpikes = RunThetaNeuronNumerically(maxNumOutputSpikes);
354 var postSpikeDerivativeProducts =
new List<double>();
356 foreach (var spikeStat
in neuronFiringHistory.SpikeStats)
358 if (previousSpikeStat == null)
360 previousSpikeStat = spikeStat;
364 postSpikeDerivativeProducts.Add(((1 + Math.Cos(spikeStat.PostSpikeState.StateVariable)) *
365 (Math.Pow(Math.Tan(spikeStat.PreSpikeState.StateVariable / 2), 2) + Alpha * Io)) /
366 StateDerivative(previousSpikeStat.PostSpikeState.StateVariable));
367 previousSpikeStat = spikeStat;
370 return postSpikeDerivativeProducts;
381 var nHatPostSpikeState = Double.NaN;
382 var nHatPreSpikeState = Double.NaN;
383 var nHatWeight = Double.NaN;
384 var spikesProcessed = 0;
385 var inputSynapses = Weights.Select(x => x.Key).ToList();
389 OutputSpikeTimeToInputSpikeTimeDerivative = 0, OutputSpikeTimeToWeightDerivative = 0
394 return outputSpikeTimeDerivatives;
397 var actualFiringTime = neuronFiringHistory.OutputSpikes.First().Time;
398 foreach (var spikeStat
in neuronFiringHistory.SpikeStats.TakeWhile(spikeStat => spikeStat.PreSpikeState.Time < actualFiringTime))
400 nHatPreSpikeState = spikeStat.PreSpikeState.StateVariable;
401 nHatPostSpikeState = spikeStat.PostSpikeState.StateVariable;
402 nHatWeight = spikeStat.Weight;
405 var nHat = spikesProcessed - 1;
408 if (spikesProcessed == 0)
410 return outputSpikeTimeDerivatives;
414 if (neuronFiringHistory.SpikeStats.Count == 1)
416 var temp = (Math.Pow(Math.Tan(nHatPreSpikeState / 2), 2) + Alpha * Io);
417 outputSpikeTimeDerivatives[neuronFiringHistory.SpikeStats.First().
Synapse] =
420 OutputSpikeTimeToInputSpikeTimeDerivative = temp / (temp + Math.Pow(Alpha * nHatWeight, 2) + 2 * Alpha * nHatWeight + Math.Tan(nHatPreSpikeState / 2)),
421 OutputSpikeTimeToWeightDerivative = -Alpha / (Math.Pow(Math.Tan(nHatPostSpikeState / 2), 2) + Alpha * Io)
423 return outputSpikeTimeDerivatives;
427 var nHatPostSpikeStateDerivative = StateDerivative(nHatPostSpikeState);
428 var postSpikeDerivativeProducts = CalculatePostSpikeDerivatives(neuronFiringHistory);
430 foreach (var spikeStat
in neuronFiringHistory.SpikeStats)
433 for (var j = n; j < nHat; j++)
435 prod *= postSpikeDerivativeProducts[j];
437 var gamma = -spikeStat.Weight * (Alpha * spikeStat.Weight + 2 * Math.Tan(spikeStat.PreSpikeState.StateVariable / 2));
438 var weightDerivative = ((-Alpha * (1 + Math.Cos(spikeStat.PostSpikeState.StateVariable))) / nHatPostSpikeStateDerivative) * prod;
439 outputSpikeTimeDerivatives[spikeStat.Synapse]=
442 OutputSpikeTimeToWeightDerivative = weightDerivative,
443 OutputSpikeTimeToInputSpikeTimeDerivative = gamma * weightDerivative
448 return outputSpikeTimeDerivatives;
460 State.StateVariable = 2 * Math.Atan(Alpha * weight + Math.Tan(State.StateVariable / 2));
465 return new List<Spike>();
475 var outputSpikeTimes =
new List<Spike>();
476 var deltaTime = newTime - State.Time;
477 var initialState = State;
478 var c2 = GetC2(deltaTime);
484 var thm = 2 * Math.Atan(c2);
485 if (thm < initialState.StateVariable || deltaTime > Period)
487 outputSpikeTimes.Add(
new Spike {NeuronIndex = NeuronIndex , Time = NextSpikeTime});
490 if (deltaTime > Period)
492 var revCount = Math.Floor(deltaTime/Period);
493 for (var k = 2; k < revCount; k++)
495 outputSpikeTimes.Add(
new Spike { NeuronIndex = NeuronIndex, Time = outputSpikeTimes.Last().Time + Period });
497 if (outputSpikeTimes.Last().Time + Period < newTime)
499 outputSpikeTimes.Add(
new Spike { NeuronIndex = NeuronIndex, Time = outputSpikeTimes.Last().Time + Period });
503 State.StateVariable = thm;
511 if (RemainingTimeToSpike < deltaTime)
513 outputSpikeTimes.Add(
new Spike { NeuronIndex = NeuronIndex, Time = NextSpikeTime });
515 State.StateVariable = 2*Math.Atan(c2);
517 if (outputSpikeTimes.Count > 0)
519 State.StateVariable = PostSpikeState;
523 State.Time = newTime;
524 return outputSpikeTimes;
532 private double GetC2(
double deltaTime)
536 return Beta * (C1 + Math.Tanh(-Beta * deltaTime)) / (1 + C1 * Math.Tanh(-Beta * deltaTime));
538 return Beta * (C1 + Math.Tan(Beta * deltaTime)) / (1 - C1 * Math.Tan(Beta * deltaTime));
OperatingRegion
Operating Region Enum
override string ToString()
The Neuron Properties As A String
override List< double > CalculatePostSpikeDerivatives(NeuronFiringHistory neuronFiringHistory)
Calculates Post Spike Derivatives, that is the derivate of the state after the current input spike re...
Spiking Neuron Abstract Class, Inherits From ISpikingNeuron
ThetaNeuron()
Creates a new instance of ThetaNeuron with no inputs
override Dictionary< Synapse, NeuronDerivativeParameters > CalculateOutputSpikeTimeDerivatives(NeuronFiringHistory neuronFiringHistory)
Calculates Output Spike Derivatives, that is the derivate of the output spike time relative to both t...
Neuron Derivative Parameters Class
override IEnumerable< Spike > AdvanceNeuronState(double newTime)
Advances the neuron's state to newTime
ThetaNeuron(int numInputs=3, double weightIni=1e6, double newIo=DefaultIo)
Creates a new instance of ThetaNeuron with a given number of inputs and an initial weight and baselin...
List< Spike > OutputSpikes
Gets or sets a list of output spikes produced during this neuron firing history
ThetaNeuron(SpikingNeuronNetwork network, int neuronIndex, double newIo=DefaultIo)
Creates a new instance of ThetaNeuron an associates it to a network
override List< Spike > RunThetaNeuron(List< Spike > inputSpikes, int maxNumOutputSpikes=MaxNumOutputSpikes)
Runs the theta neuron, advancing the state and producing up to maxNumOutputSpikes output spikes in re...
The spike statistics class
override ISpikingNeuron Clone()
Clones a neuron by removing network association
Spiking Neuron Network Class
override double StateDerivative(double phase)
Computes the derivative of the state relative to time
ThetaNeuron(IReadOnlyList< double > weights, double newIo=DefaultIo)
Creates a new instance of ThetaNeuron with given weights
Neuron Firing History Class
override IEnumerable< Spike > UpdateStateVariableOnSpike(double weight)
Updates the neuron's state variable (phase), given a spike is currently being received on a synapse w...