1 namespace SpikingNeuronNetwork.Lib
6 using System.Collections.Generic;
18 public int Id {
get; set; }
23 public IList<int> NumNeuronsPerLayer {
get;
private set; }
30 get {
return _weightMatrix.Cols - NumNeuronsPerLayer.Sum(); }
38 get {
return _isLayered; }
41 private Dictionary<int, SpikingNeuron> _neurons;
42 private const double Epsilon = 1e-10;
43 private readonly
Matrix _weightMatrix;
44 private readonly Random _random =
new Random();
45 private readonly
bool _isLayered;
55 public SpikingNeuronNetwork(
int numInputs,
int numNeurons, Type neuronType,
double weightIni = 1e6, Dictionary<string, string> neuronProperties = null)
58 NumNeuronsPerLayer =
new List<int> {numNeurons};
59 _isLayered = numNeurons == 1;
60 _weightMatrix = weightIni > 100 ?
61 Matrix.RandomMatrix(numInputs + numNeurons, numInputs + numNeurons, 1.0, 0.5) :
62 Matrix.ConstantMatrix(numInputs + numNeurons, numInputs + numNeurons, weightIni);
66 for (var i = 0; i < _weightMatrix.Cols; i++)
68 _weightMatrix[i, i] = 0;
72 for (var i = 0; i < numInputs; i++)
73 for (var n = 0; n < _weightMatrix.Rows; n++)
74 _weightMatrix[n, i] = 0;
76 AssignNeurons(numInputs, numNeurons, neuronType, neuronProperties);
87 public SpikingNeuronNetwork(
int numInputs, IList<int> numNeuronsPerLayer, Type neuronType,
double weightIni = 1e6, Dictionary<string, string> neuronProperties = null)
89 NumNeuronsPerLayer = numNeuronsPerLayer;
91 var numNeurons = numNeuronsPerLayer.Sum();
92 var totalNeurons = numInputs + numNeurons;
94 _weightMatrix = Matrix.ZeroMatrix(totalNeurons, totalNeurons);
96 const double probability = 0.5;
97 const int dispersion = 1;
99 for (var j = 0; j < numInputs; j++)
101 for (var k = numInputs; k < numInputs + numNeuronsPerLayer[0]; k++)
103 var newWeight = weightIni > 100 ? ((_random.NextDouble() <= probability) ? dispersion * 2 * (_random.NextDouble() - 0.5) : 0) : weightIni;
104 _weightMatrix[j, k] = newWeight;
108 for (var layer = 1; layer < numNeuronsPerLayer.Count; layer++)
110 for (var j = numInputs; j < numInputs + numNeuronsPerLayer.Take(layer).Sum(); j++)
112 for (var k = numInputs + numNeuronsPerLayer.Take(layer).Sum();
113 k < numInputs + numNeuronsPerLayer.Take(layer + 1).Sum();
116 var newWeight = weightIni > 100
117 ? ((_random.NextDouble() <= probability)
118 ? dispersion * 2 * (_random.NextDouble() - 0.5)
121 _weightMatrix[j, k] = newWeight;
128 for (var i = 0; i < _weightMatrix.Cols; i++)
130 _weightMatrix[i, i] = 0;
134 for (var i = 0; i < numInputs; i++)
135 for (var n = 0; n < _weightMatrix.Rows; n++)
136 _weightMatrix[n, i] = 0;
138 AssignNeurons(numInputs, numNeurons, neuronType, neuronProperties);
149 private SpikingNeuronNetwork(Random random,
Matrix weightMatrix,
bool isLayered, IList<int> numNeuronsPerLayer, Dictionary<int, SpikingNeuron> neurons)
152 _weightMatrix = weightMatrix;
153 _isLayered = isLayered;
155 NumNeuronsPerLayer = numNeuronsPerLayer;
164 var newNeurons = _neurons.ToDictionary(kvp => kvp.Key, kvp => (
SpikingNeuron) kvp.Value.Clone());
165 var clonedNetwork =
new SpikingNeuronNetwork(_random, _weightMatrix, _isLayered, NumNeuronsPerLayer, newNeurons);
166 foreach (var neuronIndices
in newNeurons.Keys)
168 newNeurons[neuronIndices].NeuronNetwork = clonedNetwork;
170 return clonedNetwork;
180 return _neurons[neuronIndex].Clone();
191 return _neurons[neuronFiringHistory.NeuronIndex].CalculatePostSpikeDerivatives(neuronFiringHistory);
202 return _neurons[neuronFiringHistory.NeuronIndex].CalculatePostSpikeDerivativesNumerical(neuronFiringHistory);
213 return _neurons[neuronFiringHistory.NeuronIndex].CalculateOutputSpikeTimeDerivatives(neuronFiringHistory);
224 return _neurons[neuronFiringHistory.NeuronIndex].CalculateOutputSpikeTimeDerivativesNumerical(neuronFiringHistory);
235 double currentTime = 0;
236 const double endTime = 500;
237 var neuronFiringHistories =
new Dictionary<int, NeuronFiringHistory>();
239 spikeQueue.AddRange(inputSpikes);
240 foreach (var neuron
in _neurons)
242 spikeQueue.Add(
new Spike { Time = neuron.Value.NextSpikeTime, NeuronIndex = neuron.Value.NeuronIndex});
246 while (currentTime < endTime && spikeQueue.Count > 0)
249 var currentSpike = spikeQueue.Dequeue();
250 currentTime = currentSpike.Time;
254 if (currentSpike.NeuronIndex > NumInputs - 1)
256 if (neuronFiringHistories.ContainsKey(currentSpike.NeuronIndex))
258 neuronFiringHistories[currentSpike.NeuronIndex].OutputSpikes.Add(currentSpike);
264 NeuronIndex = currentSpike.NeuronIndex,
265 OutputSpikes =
new List<Spike> { currentSpike },
269 _neurons[currentSpike.NeuronIndex].State.Time = currentSpike.Time;
270 _neurons[currentSpike.NeuronIndex].State.StateVariable = _neurons[currentSpike.NeuronIndex].PostSpikeState;
274 var outputNeurons = GetNeuronsOutputNeurons(currentSpike.NeuronIndex);
277 foreach (var outputNeuron
in outputNeurons)
279 var oldSpike =
new Spike {Time = outputNeuron.NextSpikeTime, NeuronIndex = outputNeuron.NeuronIndex};
281 var outputSpikeList = outputNeuron.ProcessSpike(currentSpike, out currentSpikeStats);
282 if (neuronFiringHistories.ContainsKey(outputNeuron.NeuronIndex))
284 neuronFiringHistories[outputNeuron.NeuronIndex].OutputSpikes.AddRange(outputSpikeList);
285 neuronFiringHistories[outputNeuron.NeuronIndex].SpikeStats.Add(currentSpikeStats);
291 NeuronIndex = outputNeuron.NeuronIndex,
292 OutputSpikes =
new List<Spike>(outputSpikeList),
293 SpikeStats = currentSpikeStats == null ?
new SortedSet<SpikeStats>() :
new SortedSet<SpikeStats> {currentSpikeStats}
298 spikeQueue.Update(oldSpike, outputNeuron.NextSpikeTime);
302 return neuronFiringHistories;
310 foreach (var neuron
in _neurons)
312 neuron.Value.ResetState();
323 return _neurons[neuronIndex].Weights.Select(x => x.Key).ToList();
333 var weights = _weightMatrix.GetRow(neuronIndex);
334 var outputNeuronIndices = weights.FindAllIndexOfNot(0);
335 return outputNeuronIndices
336 .Select(outputNeuronIndex =>
new Synapse(neuronIndex, outputNeuronIndex))
347 if (!IsLayered || layerIndex >= NumNeuronsPerLayer.Count)
351 var startIndex = NumInputs + NumNeuronsPerLayer.Where((x,i) => i < layerIndex).Sum();
352 return Enumerable.Range(startIndex, NumNeuronsPerLayer[layerIndex]).ToList();
361 return GetNeuronIndicesByLayer(NumNeuronsPerLayer.Count - 1);
369 internal double GetSynapticWeight(
Synapse synapse)
371 if (synapse.
InputNeuronIndex > _weightMatrix.Rows)
throw new ArgumentException(
"Invalid Synapse: " + synapse);
372 if (synapse.
OutputNeuronIndex > _weightMatrix.Cols)
throw new ArgumentException(
"Invalid Synapse: " + synapse);
373 return _weightMatrix[synapse.InputNeuronIndex, synapse.OutputNeuronIndex];
381 internal Dictionary<Synapse, double> GetNeuronWeights(
int neuronIndex)
383 if (neuronIndex > _weightMatrix.Cols)
return null;
384 var weights =
new Dictionary<Synapse, double>();
385 var col = _weightMatrix.GetCol(neuronIndex);
386 for (var j = 0; j < col.Rows; j++)
388 if (Math.Abs(col[j, 0]) > Epsilon)
390 weights.Add(
new Synapse(j, neuronIndex), col[j, 0]);
401 internal void SetSynapticWeight(Synapse synapse,
double newValue)
403 if (synapse.InputNeuronIndex > _weightMatrix.Rows || synapse.OutputNeuronIndex > _weightMatrix.Cols)
return;
404 _weightMatrix[synapse.InputNeuronIndex, synapse.OutputNeuronIndex] = newValue;
412 internal List<SpikingNeuron> GetNeuronsOutputNeurons(
int neuronIndex)
414 var weights = _weightMatrix.GetRow(neuronIndex);
415 var outputNeuronIndices = weights.FindAllIndexOfNot(0);
416 return outputNeuronIndices.Where(_neurons.ContainsKey)
417 .Select(x => _neurons[x])
428 private void AssignNeurons(
int numInputs,
int numNeurons, Type neuronType, Dictionary<string,string> neuronProperties = null)
430 _neurons =
new Dictionary<int, SpikingNeuron>();
431 if (!typeof(ISpikingNeuron).IsAssignableFrom(neuronType))
433 throw new ArgumentException(
"Neuron type " + neuronType.Name +
" must derive from ISpikingNeuron");
436 var neuronConstructor = neuronType.GetConstructor(
new Type[] { });
437 if (neuronConstructor == null)
439 throw new ArgumentException(
"Neuron type " + neuronType.Name +
" must implement an empty constructor");
441 foreach (var neuronIndex
in Enumerable.Range(numInputs, numNeurons))
443 _neurons.Add(neuronIndex, (SpikingNeuron)neuronConstructor.Invoke(
new object[] { }));
444 _neurons[neuronIndex].NeuronNetwork =
this;
445 _neurons[neuronIndex].NeuronIndex = neuronIndex;
446 var typeProperties = neuronType.GetProperties();
447 foreach (var neuronProperty
in neuronProperties ??
new Dictionary<string, string>())
449 var typeProperty = typeProperties.First(x => x.Name == neuronProperty.Key);
450 if (typeProperty == null || !typeProperty.CanWrite)
continue;
451 var propType = typeProperty.PropertyType;
453 if (propType.BaseType != null && propType.BaseType.Name ==
"Enum")
455 castedValue = Enum.Parse(propType, neuronProperty.Value);
459 castedValue = Convert.ChangeType(neuronProperty.Value, propType);
462 typeProperty.SetValue(_neurons[neuronIndex], castedValue);
464 _neurons[neuronIndex].ResetState();
SpikingNeuronNetwork(int numInputs, IList< int > numNeuronsPerLayer, Type neuronType, double weightIni=1e6, Dictionary< string, string > neuronProperties=null)
Creates a Spiking Neuron Network Object with a Layered Topology
List< double > CalculatePostSpikeDerivatives(NeuronFiringHistory neuronFiringHistory)
Calculates Post Spike Derivatives for a specific neuron, that is the derivate of the state after the ...
void ResetNetwork()
Resets the network to its initial state
List< Synapse > GetNeuronsOutputSynapses(int neuronIndex)
Get a list of output synapses for a specific neuron
SpikingNeuronNetwork Clone()
Creates a deep copy of the spiking neuron network
SpikingNeuronNetwork(int numInputs, int numNeurons, Type neuronType, double weightIni=1e6, Dictionary< string, string > neuronProperties=null)
Creates a Spiking Neuron Network Object With Random Connectivity Topology
Spiking Neuron Abstract Class, Inherits From ISpikingNeuron
Dictionary< Synapse, NeuronDerivativeParameters > CalculateOutputSpikeTimeDerivatives(NeuronFiringHistory neuronFiringHistory)
Calculates Output Spike Derivatives for a specific neuron, that is the derivate of the output spike t...
List< int > GetOutputLayerNeuronIndices()
Gets a list of output layer neuron indices
Spike Priority Queue used for determining what spike to process next based on spike timing ...
Dictionary< int, NeuronFiringHistory > RunSpikingNeuronNetwork(List< Spike > inputSpikes)
Runs the spiking neuron network, processing the effect of all input spikes
List< int > GetNeuronIndicesByLayer(int layerIndex)
Gets a list of neuron indices by layer
int InputNeuronIndex
Gets or sets the index of the input neuron.
The spike statistics class
Spiking Neuron Network Class
ISpikingNeuron GetStandAloneNeuron(int neuronIndex)
Gets the stand alone neuron.
List< double > CalculatePostSpikeDerivativeNumerical(NeuronFiringHistory neuronFiringHistory)
Calculates Post Spike Derivatives numerically for a specific neuron, that is the derivate of the stat...
List< Synapse > GetNeuronsInputSynapses(int neuronIndex)
Get a list of input synapses for a specific neuron
Dictionary< Synapse, NeuronDerivativeParameters > CalculateOutputSpikeTimeDerivativesNumerical(NeuronFiringHistory neuronFiringHistory)
Calculates Output Spike Derivatives numerically for a specific neuron, that is the derivate of the ou...
Neuron Firing History Class
int OutputNeuronIndex
Gets or sets the index of the output neuron.