I've just implemented learning in the model as well, here's the abstraction I'm using for synapses that learn with STDP:
Code:
class Synapse{
float w; //current weight
int pre = 0; //time since the last presynaptic
//spike (0 means no spike, 1 means
//spike this frame, 2 means last
//frame was a spike, etc.)
float preT = 1.4; //presynaptic spike threshold
int post = 0; //time since the last postsynaptic spike
float postT = 1.4;//postsynaptic spike threshold
//STDP learning rule
//http://en.wikipedia.org/wiki/Spike_timing_dependent_plasticity
//index 4 => (pre - post) == 0
//(NB: this can be changed to 5 for auto-associativity)
float[] STDPvals = {0,-0.1,-0.2,-0.4,-1.0,1.0,0.4,0.2,0.1,0};
Synapse(float w, float preT, float postT){
this.w = w;
this.preT = preT;
this.postT = postT;
}
Synapse(float w){
this.w = w;
}
float update(float n1, float n2){
w = newWeight(n1,n2);
return w;
}
float newWeight(float n1, float n2){
if(pre == 0 && post == 0){
pre = (n1 >= preT ? 1 : 0 ); //spike or no spike?
post = (n2 >= postT ? 1 : 0 );
}
else if(pre == 0 && post > 0){
post += 1; //increment postsynaptic spike counter
pre = (n1 >= preT ? 1 : pre ); //spike? if not don't change the counter
post = (n2 >= postT ? 1 : post );
}
else if(pre > 0 && post == 0){
pre += 1; //increment presynaptic spike counter
pre = (n1 >= preT ? 1 : pre );
post = (n2 >= postT ? 1 : post );
}
else{
System.out.println("Call the doctor");
}
//when we have a pre and post spike pair,
//we change the synaptic weight (plasticity)
if(pre >= 1 && post >= 1){
int sh = limit09(4 + pre - post); // <-- Here
//is where you can change the 4 to a 5
//for auto-associativity
pre = post = 0;
//for debugging:
//System.out.println(sh);
return calcWeight(w,STDPvals[sh]);
}
else{
return w;
}
}
//sigmoid limits range to 0.0 .. 1.0
float calcWeight(float w, float p){
return sigmoid(2*(float)Math.PI*w*(1 + p));
}
//limit to array length (tmtowtdi)
int limit09(int n){
return (n<0 ? 0 : (n>9 ? 9 : n));
}
float getWeight(){
return w;
}
float sigmoid(float t){
return 1/(1+pow(e,-t)); //float e = (float)Math.E;
}
}
To implement this, I've just replaced the matrix of floats I used before with a matrix of Synapse objects, and perform the synapse update when the inputs to each neuron are assembled.