In [1]:
    
from IPython.display import HTML;HTML('<center><div style="font-size:1.5em"><iframe width="80%" height="700" src="http://www.youtube.com/embed/DUZldskw51A" loop=1 allowfullscreen></iframe><br><a target="_blank" href="/notebooks/furtherFormulas/3dAnimScatterPlotHdf5.ipynb">Animation</a> <a target="_blank" href="/github/tartavull/snn-rl/blob/master/testVoltage.mp4">Video Download</a></div></center>')
    
    Out[1]:
In [2]:
    
from IPython.display import HTML;HTML('<center><br><div style="font-size:1.5em">Weights of All Neurons During the Training Process with 4 Characters<br><br><iframe width="60%" height="500" src="http://www.youtube.com/embed/-ae2j13XQBU" loop=1 allowfullscreen></iframe><br><a target="_blank" href="/github/tartavull/snn-rl/blob/master/furtherFormulas/3dBarChartAnim.ipynb#returnNewW">3dBarChartAnim</a></div></center>')
    
    Out[2]:
In [3]:
    
from IPython.display import HTML;HTML('<center><br><div style="font-size:1.5em">Weights of All Neurons After Training with 26 Characters<br><br><iframe width="60%" height="500" src="http://www.youtube.com/embed/8R_BrMk8VYM" loop=1 allowfullscreen></iframe><br><a target="_blank" href="/github/tartavull/snn-rl/blob/master/furtherFormulas/3dBarChartRotatingAnim.ipynb#returnNewW">3dBarChartRotatingAnim</a></div></center>')
    
    Out[3]:
In [4]:
    
from IPython.display import HTML;HTML('<center><div style="font-size:1.5em">Relationship Between Weight, Tau, and Resistance:<br><br></div><iframe width="60%" height="500" src="http://www.youtube.com/embed/f9QN9Q1FqPY" loop=1 allowfullscreen></iframe><br><div style="font-size:1.5em"><a target="_blank" href="/github/tartavull/snn-rl/blob/master/furtherFormulas/3dBarWTauRAnim.ipynb#returnNewW">3dBarWTauRAnim</a></div></center>')
    
    Out[4]:
In [ ]:
    
'''
	Copyright 2015, Nate Sutton and Ignacio Tartavull
	This is the main file for the Spiking Neual Networks
	Reinforcement Learning simulation.  
	More info:
	https://github.com/tartavull/snn-rl/blob/master/README.md
	http://nbviewer.ipython.org/github/tartavull/snn-rl/blob/master/notebooks/introduction.ipynb
	http://nbviewer.ipython.org/github/tartavull/snn-rl/blob/master/FFSSN.ipynb
'''
from furtherFormulas.architecture_further_formulas import *
from furtherFormulas.cofactorCalculations import *
from furtherFormulas.timeAndRefracCalcs import *
from furtherFormulas.outputPrinting import *
from furtherFormulas.testingProcesses import *
from furtherFormulas.lateralInhibition import *
from furtherFormulas.generalUtilities import *
timeAndRefrac = timeAndRefrac	
class gupta_paper:
	'''
		Main program variables are set the simulation is run.  Specific neuron models are
		defined for computing processing of electrophysiology in the soma, direct to soma
		signals, and active dendrites.  Equations with variables
		are defined in the equations() objects.
	'''
	neuralnet = Network()
	dictionary = dictionary()
	spiketimes = dictionary.spikeTimes(dictionaryLongitude, spikeInterval, testingSpikesPerChar, testingEpochs)
	trainingSpikeTimes = dictionary.spikeTimes(dictionaryLongitude, spikeInterval, trainingSpikesPerChar, trainingEpochs)
	LIK = SpikeGeneratorGroup(N=15, indices=spiketimes[:,0], times=spiketimes[:,1]*ms)
	# W = W and other lines below are to avoid an odd 'reference before assignment' error
	W = W
	tauM = tauM
	neuronIndex = neuronIndex
	generalClockDt = generalClockDt
	runTime = runTime
	runTimeScaling = runTimeScaling
	evaluateClassifier = evaluateClassifier
	accelerateTraining = accelerateTraining
	diracScaling = diracScaling
	somaDirectScaling = somaDirectScaling
	negativeWeightReinforcement = negativeWeightReinforcement
	positiveWeightReinforcement = positiveWeightReinforcement
	timeAndRefrac = timeAndRefrac	
	testRun = testRun
	latInhibSettings = latInhibSettings
	standardPrint = standardPrint
	verbosePrint = verbosePrint
	testingRunTime = testingRunTime
	optResultsFile = optResultsFile
	minWeightsRand = minWeightsRand
	maxWeightsRand = maxWeightsRand
	totalSpikeIntervals = totalSpikeIntervals
	def run_model(self):
		neuralnet = self.neuralnet
		dictionary = self.dictionary
		eqs = Equations('''
			dv/dt = v/(1*second): volt
			dprelimV/dt = (-prelimV+((Rm/mV)*(SynI+DendI*1.0)))/(tauM) : volt (unless refractory)
			Rm = 80*mV : volt
			tauM = 30*ms : second
	        V : volt
	        DendI : volt
	        SynI : volt
	        v2 : volt	
			UmSpikeFired : volt	
			beginRefrac : volt
		    ''')			
		dendriteEqs = Equations('''
			dv/dt = (((-v/mV)+((r/mV)*(w/volt)*(dirac/volt)))/(tau))*mV : volt
			V : volt
	        r : volt
	        w : volt
	        dirac : volt
	        tau : second
	        v2: volt
			''')
		directToSomaEqs = Equations('''
			dv/dt = (((-v/mV)+(summedWandDirac/volt))/(tauS))*mV : volt
			tauS = 2*ms : second
			V : volt
			summedWandDirac : volt
			v2 : volt
			spikeFired : boolean
			''')		
		class ADDSNeuronModel(NeuronGroup, gupta_paper): 
			'''
				This is the model used for electrophysiology occuring in the Soma
			'''
			neuronIndex = self.neuronIndex
			generalClockDt = self.generalClockDt
			def __init__(self, params):
				self = parseArgs(self, sys.argv, dictionaryLongitude)		
				NeuronGroup.__init__(self, N=dictionaryLongitude, model=eqs,threshold='v>10*mV', reset='v=-0.002 * mV; dv=0; v2=10*mV;UmSpikeFired=1*mV;beginRefrac=1*mV;inhibitionVoltage=prelimV',refractory=8*ms,clock=Clock(dt=self.generalClockDt))
				@network_operation(dt=self.generalClockDt)
				def additionToNetwork(): 
					neuronIndex = self.neuronIndex
					timeAndRefrac.spikeIntervalCounter = (floor(timeAndRefrac.time/timeAndRefrac.spikeIntervalUnformatted) * timeAndRefrac.spikeIntervalUnformatted)*10
					def dendCalcs(neuronIndex, ADDSObj, dendObj, spiketimes, evaluationActive):
						'''
							Below sequentially Dirac, Tau, then Resistance are calculated every end of a spike-time interval.
							The resulting Dend I is added to the Um calc for the ADDS soma.
						'''
						timeAndRefrac = self.timeAndRefrac
						# Dirac
						dendObj[neuronIndex].dirac = diracCalc(dendObj, neuronIndex, spiketimes, timeAndRefrac.time, timeAndRefrac.lastSpikeInterval)
						# Initialize weights
						if (evaluationActive==False and timeAndRefrac.time == 0.000):
							dend[neuronIndex].w = W[neuronIndex]*volt
						if (evaluationActive==False and timeAndRefrac.refractoryPointSwitch==True):
							# Only change weights of neuron fired
							if ADDSObj.UmSpikeFired[neuronIndex] == 1*mV:
								# Weights
								WeightChangeCalculation(neuronIndex, spiketimes, timeAndRefrac.time, self.negativeWeightReinforcement, self.positiveWeightReinforcement, M, dendObj)	
							# Tau
							tauDCalc(neuronIndex, dendObj)
							# Resistance
							resistanceCalc(neuronIndex, dendObj, self.tauM)
						# TODO: check do I need additional loop below?
						for indexOfDend in range(dictionaryLongitude):
							ADDSObj.DendI[indexOfDend] = sum(dendObj[indexOfDend].v[:])*dendCalcScaling
						#print 'ADDSObj.t',ADDSObj.t,'ADDSObj.DendI',ADDSObj.DendI,'neuronIndex',neuronIndex,'dendObj[neuronIndex].dirac',dendObj[neuronIndex].dirac,'dendObj[neuronIndex].tau',dendObj[neuronIndex].tau,'dendObj[neuronIndex].w',dendObj[neuronIndex].w,'dendObj[neuronIndex].r',dendObj[neuronIndex].r
					def somaDirectCalcs(neuronIndex, ADDSObj, somaDirectObj, dendObj):
						dotProductWandDirac =  sum(w*d for w,d in zip(dendObj[neuronIndex].w[:], dendObj[neuronIndex].dirac[:]))
						#somaDirectObj.summedWandDirac[neuronIndex] = ((dotProductWandDirac*volt)/(volt**2))*self.somaDirectScaling
						somaDirect.summedWandDirac[neuronIndex] = ((dotProductWandDirac*volt)/(volt**2))*self.somaDirectScaling
						for neuronNumber in range(dictionaryLongitude):
							#ADDSObj.SynI[neuronNumber] = somaDirectObj.v[neuronNumber]		
							ADDS.SynI[neuronNumber] = somaDirect.v[neuronNumber]		
						#print 'ADDSObj.t',ADDSObj.t,'ADDSObj.SynI',ADDSObj.SynI,'neuronIndex',neuronIndex,'somaDirectObj.summedWandDirac',somaDirectObj.summedWandDirac[neuronIndex],'dendObj[neuronIndex].w',dendObj[neuronIndex].w,'dendObj[neuronIndex].dirac',dendObj[neuronIndex].dirac
					def mainSimulationCalcs(ADDSObj, dendObj, somaDirectObj, spiketimes, evaluationActive):
						'''
							dend then somaDirect calcs are done which are then used to set lat inhib.
							Soma Um calcs are done automatically using equations entered for brian
							once dend and somaDirect are updated
						'''
						preTNorm = self.timeAndRefrac.time
						tNorm = preTNorm - (floor((preTNorm/.001)*.01) * .1)
						
						self.timeAndRefrac = timePeriodAndRefractoryCalcs(self.timeAndRefrac)
						if (evaluationActive==True) and (timeAndRefrac.time == 0.000 or timeAndRefrac.time == 0.001):
							initializeTrainedModelParameters(dendObj)
						# Option to accelerate computations for training
						if self.accelerateTraining == False or (evaluationActive == False and (tNorm <= .005 or tNorm >= .096)):													
							if self.accelerateTraining == True and (tNorm >= .096 and tNorm < .099):
								for i in range(dictionaryLongitude):
									ADDSObj.DendI[i]=0*mV
									ADDSObj.SynI[i]=0*mV
									ADDSObj.prelimV[i]=0*mV
									ADDSObj.v[i]=0*mV								
									for i2 in range(len(dend[0].v)):
										dendObj[i].v[i2] = 0*mV
									somaDirectObj.v[i] = 0*mV		
							for neuronIndex in range(dictionaryLongitude):
								dendCalcs(neuronIndex, ADDSObj, dendObj, spiketimes, evaluationActive)
								somaDirectCalcs(neuronIndex, ADDSObj, somaDirectObj, dendObj)								
							ADDSObj.v, self.latInhibSettings = lateralInhibition(ADDSObj, self.timeAndRefrac, self.latInhibSettings)
							#if ADDSObj.t > 100*ms:
								#for i in range(dictionaryLongitude):
								#	somaDirectObj.summedWandDirac[i] += 20*mV
								#print 'ADDS.t',ADDS.t,'ADDS.SynI',ADDS.SynI,'ADDS.DendI',ADDS.DendI,'ADDSObj.v',ADDSObj.v,'somaDirectObj.summedWandDirac',somaDirectObj.summedWandDirac,'somaDirectObj.v',somaDirectObj.v
							for neuronIndex in range(dictionaryLongitude): 
								ADDSObj.v2, somaDirectObj.v2, self.timeAndRefrac = checkForResets(neuronIndex, ADDSObj, dendObj, somaDirectObj, self.timeAndRefrac)
							ADDSObj.UmSpikeFired, self.testRun = evaluateClassifierPerf2(ADDSObj, self.testRun)
						#roundedSecondsTime = math.floor(Decimal(format((ADDSObj.t), '.1f'))/Decimal(format((1.0*second), '.1f')))
						#if printWeights < roundedSecondsTime:
						#	self.printWeights = roundedSecondsTime; printWeights(dendObj);
					if self.evaluateClassifier == False:
						mainSimulationCalcs(ADDS, dend, somaDirect, self.trainingSpikeTimes, False)
					else:
						mainSimulationCalcs(ADDS, dend, somaDirect, self.spiketimes, True)					
				self.contained_objects.append(additionToNetwork)				
		class DendriteNeuronModel(NeuronGroup):
			generalClockDt = self.generalClockDt
			def __init__(self, params): 
				NeuronGroup.__init__(self, N=15, model=dendriteEqs,clock=Clock(dt=self.generalClockDt))
				@network_operation(dt=self.generalClockDt)
				def additionToNetwork(): 
					placeHolderForLaterContent = True
				self.contained_objects.append(additionToNetwork)
		class SomaDirectNeuronModel(NeuronGroup): 
			generalClockDt = self.generalClockDt
			def __init__(self, params): 
				NeuronGroup.__init__(self, N=dictionaryLongitude, model=directToSomaEqs,clock=Clock(dt=self.generalClockDt))
				@network_operation(dt=self.generalClockDt)
				def additionToNetwork(): 
					placeHolderForLaterContent = True
				self.contained_objects.append(additionToNetwork)		
		dend = [None]*dictionaryLongitude
		weightMonitors = [None]*dictionaryLongitude
		for firstLayerIndex in range(dictionaryLongitude):
			dend[firstLayerIndex] = DendriteNeuronModel(15)	
			weightMonitors[firstLayerIndex] = StateMonitor(dend[firstLayerIndex], 'w', record=True)
			neuralnet.add(dend[firstLayerIndex])
			neuralnet.add(weightMonitors[firstLayerIndex])
		somaDirect = SomaDirectNeuronModel(dictionaryLongitude)
		neuralnet.add(somaDirect)
		ADDS = ADDSNeuronModel(self)			
		M = SpikeMonitor(ADDS)
		Mv = StateMonitor(ADDS, 'V', record=True)
		UmM = StateMonitor(ADDS, 'v2', record=True)
		self.M = M # for ipython compatibility
		self.UmM = UmM 
		self.weightMonitors = weightMonitors
		neuralnet.add(ADDS)
		neuralnet.add(M)
		neuralnet.add(UmM)
		if (ADDS.evaluateClassifier==True): ADDS.runTime = ADDS.testingRunTime
		ADDS.runTime *= ADDS.runTimeScaling # scaling factor
		if ADDS.standardPrint: neuralnet.run(ADDS.runTime,report='text')
		else: neuralnet.run(ADDS.runTime,report='stderr')
		OutputEvaluationResults(dend, self.testRun, ADDS.verbosePrint, ADDS.evaluateClassifier)
		accuracyPerc = totalCorrectPercentage()
		precisionPerc = precisionPercentage()
		writeOptimizationResults(ADDS, self.testRun, accuracyPerc)
		neuronToPlot = 1
		colors = ['r']*1+['g']*1+['b']*1+['y']*1
		colors = ['blue', 'green', 'magenta', 'cyan']
		subplot(211)
		plot(M.t/ms, M.i, '.')
		legend(['A','B','C','D'], loc='upper left')			
		subplot(212)
		plot(UmM.t, UmM.v2.T/mV)	
		xlabel('Time (ms)')
		ylabel('Membrane Potential (mV)')
		if (showPlot==True):
			show()	
		return evaluateClassifier, precisionPerc
def main():
	run_gupta_paper = gupta_paper()
	evaluateClassifier, precisionPerc = run_gupta_paper.run_model()
	if evaluateClassifier: print precisionPerc
	return precisionPerc
if  __name__ =='__main__':main()