load_file("writedata.hoc") // Allow periodic saving of data to disk print "Loading alz.hoc..." // alz.hoc // Mark Rowan, School of Computer Science, University of Birmingham, UK // April 2012 // Code to Repeatedly delete neurons, allow synaptic compensation, and perform // repeat+unique trials for calculating Fourier information (Crumiller et al. 2011). // ********************************************************************** // REQUIREMENTS: // Set buffertime in writedata.hoc to an appropriate length of time (e.g. 1600e3) // run.hoc: SPKSZ should be at least 2500e3 elements (assuming buffertime=1600e3 and scale=1) // run.hoc: should have prl(0,1) as the last line in the file to turn off printlist recording // params.hoc: should have PreDur = segmentlength * (deletionstep/numcells) seconds (e.g. 160e3 s) // ********************************************************************** // Repeat until all neurons deleted (at 1600s per segment = 160 000s = ~44hrs of data): // Delete deletionstep neurons (either randomly, or proportional to scale factor) // Allow AMPA and GABA synapses to compensate (doing it in only 1600s here, not "hours to days"!) // Present alternate 80s trials of 'unique' and 'repeat' stimulation for Fourier info calculation // **** User-settable parameters **** // Scaling params declare("scaling", 1) // Set to 1 to enable compensatory homeostatic synaptic scaling declare("activitytau", 100e3) // Activity sensor time constant declare("activitybeta", 4.0e-8) // Scaling weight declare("activitygamma", 1.0e-10) // Scaling integral controller weight declare("scalingstart", buffertime) // Time after which to begin synaptic scaling (needs to be long enough for the activity sensors to reach approximately the real average firing rate) declare("scaleexternal", 1) // Should we scale down the external inputs proportionally to the network deletion? declare("scaleexternalrate", 0.25) // Vary the external scaledown constant // Deletion params declare("randomdelete", 1) // Set to 1 for uniform random deletion, or 0 for scaling-proportional deletion declare("deletionstep", 5 * scale) // Delete this many cells per round // Timing params declare("segmentlength", buffertime) // How long is allocated to one round of deletion + compensation trials? declare("infotriallength", 80e3) // Length (ms) of unique+repeat Fourier information trials numcells = 470 * scale // Number of cells in the network (set in network.hoc:77 and :124) // Recording params declare("recording_interval", 100e3) // How many ms between scalefactor/activity/etc recordings declare("recording_start", 5e3) // Start recording data after this time // Define objects objref remainingcellIDs, randgen, deletionList, auxFile, varsFile strdef auxFileName strdef varsFileName proc setup() { // Set up list of remaining undeleted cells remainingcellIDs = new Vector(numcells) remainingcellIDs.indgen(1) // Generate elements from 0 to numcells-1 // Initialise RNG randgen = new Random() // Set scaling parameters in INTF6 col.ce.o(0).setactivitytau(activitytau) col.ce.o(0).setactivitygamma(activitygamma) col.ce.o(0).setactivitybeta(activitybeta) // Create data file // filepath should already have been allocated in writedata.hoc sprint(auxFileName, "%s/%s", filepath, "aux") sprint(varsFileName, "%s/%s", filepath, "vars") auxFile = new File(auxFileName) varsFile = new File(varsFileName) header_written = 0 // Instruct write_scaling_data() to write vars file header } proc turn_on_scaling() { if (scaling) { printf("Turning on synaptic scaling\n") col.ce.o(0).setscaling(1) } } proc deletionround() { local i, deleted, temp, gain printf("*** %d cells remaining, deleting %d\n", remainingcellIDs.size(), deletionstep) deletionList = new Vector() // Reset deletionList // Obtain list of cells to be deleted (either at uniform random, or proportional to compensation) deleted = 0 while (deleted < deletionstep) { if (randomdelete) { // Delete at uniform random randgen.uniform(0, remainingcellIDs.size()) // Uniform-random over 0 to number of remaining cells temp = remainingcellIDs.x[int(randgen.repick())] // Get random cell index from remainingcellIDs } else { // TODO Delete randomly in proportion to compensation rates temp = 0 } if (!deletionList.contains(temp)) { deleted = deleted + 1 printf("Deleting cell %d\n", temp) deletionList.append(temp) // Only append index if it's unique remainingcellIDs.remove(remainingcellIDs.indwhere("==", temp)) // Remove from list of remaining cells } } for vtr(&id,deletionList) { // Delete cells in deletionList printf("Cell %d scalefactor = %f\n", id, col.ce.o(id).get_scale_factor()) // Write deletionlist and compensation rates of deleted cells to file col.ce.o(id).flag("dead",1) // Borrowed from network.hoc:dokill() //printf("%d\n", col.ce.o(id).get_id()) } if (scaleexternal) { scaledown() // Scale external input weights down as the network is deleted } // While there are still cells to delete, queue another round of deletion if (remainingcellIDs.size() > deletionstep) { cvode.event(t + segmentlength, "deletionround()") } } proc scaledown() { local c,i,vhz,a,sy,ct,idx,sdx localobj vsy,nc // Reduce strength of external inputs linearly as deletion progresses. // Should be reasonable, as if other columns (represented by external inputs) are also // suffering atrophy, their output strengths (to this model's column) will be reduced too. a=allocvecs(vsy) vsy.append(GA) vsy.append(GA2) vsy.append(AM2) vsy.append(NM2) //setwmatex() // Reinitialise weights matrix //gain = remainingcellIDs.size() / numcells gain = 1 - ((1 - (remainingcellIDs.size() / numcells)) * scaleexternalrate) printf("External input gain: %f\n", gain) // For each CSTIM in lcstim for c = 0, lcstim.count-1 { i = 0 // Increment through the NetCon objects within this CSTIM // For each NetCon in ncl (based on col.hoc proc nsstim) -- based on col.hoc proc nsstim() for sdx=0,vsy.size-1 { sy=vsy.x(sdx) // go through synapse types for ct=0,CTYPi-1 if(col.numc[ct] && wmatex[ct][sy] && ratex[ct][sy]) {//go through cell types, check weights,rates of inputs for idx = col.ix[ct], col.ixe[ct] { //printf("idx %d\n", idx) // For each cell of type ct (idx is id of the cell) // change the weights according to the new values in wmatex, scaled down by gain lcstim.o(c).ncl.o(i).weight(sy) = lcstim.o(c).wmatex[ct][sy] * gain //printf("c %d, i %d, weight %f\n", c, i, lcstim.o(c).ncl.o(i).weight(sy)) i = i + 1 // Increment to next NetCon in the list } } } } dealloc(a) } // TODO Check that CSTIMs are indeed alternating between 'fixed' and 'unique' proc repeattrialcstim() { local i,j,inputseed // Set CSTIMs to use a sequence from a fixed seed for Fourier info calculation // At 80000ms per stim, this should give 10 * repeat and 10 * unique trials in 1600s cvode.event(t + infotriallength, "uniquetrialcstim()") // Queue next 'unique' stimulation trial printf("Initiate repeat trials for %d ms\n", infotriallength) inputseed = 1234 // Fixed seed for i=0,lcol.count-1 { for j=0,lcstim.o(i).vrse.size-1 { lcstim.o(i).vrse.x[j] = inputseed+j // Store random seeds for each nstim } lcstim.o(i).initrands() // Reinitialise the external inputs' RNGs // TODO Does this restart CSTIM from t=0 (i.e. produce identical stim each time) // or does it continue from current t, thereby not producing identical stims? } } proc uniquetrialcstim() { local i,j,inputseed // Set CSTIMs to use a sequence from current sim clock time 't' for Fourier info calculation // At 80000ms per stim, this should give 10 * repeat and 10 * unique trials in 1600s cvode.event(t + infotriallength, "repeattrialcstim()") // Queue next 'repeat' stimulation trial printf("Initiate unique trials for %d ms\n", infotriallength) inputseed = t+1 // Seed set from clock (i.e. pseudo-randomly set) for i=0,lcol.count-1 { for j=0,lcstim.o(i).vrse.size-1 { lcstim.o(i).vrse.x[j] = inputseed+j // Store random seeds for each nstim } lcstim.o(i).initrands() // Reinitialise the external inputs' RNGs } } proc write_scaling_data() { local k, id, act, trg, scl, type, dead if (!header_written) { // Write vars file header varsFile.aopen() varsFile.printf("# ************* Runtime params *************\n") varsFile.printf("buffertime=%d\n", buffertime) varsFile.printf("numcells=%d\n", numcells) varsFile.printf("scaling=%d\n", scaling) varsFile.printf("scalingstart=%d\n", scalingstart) varsFile.printf("scaleexternal=%d\n", scaleexternal) varsFile.printf("scaleexternalrate=%f\n", scaleexternalrate) varsFile.printf("randomdelete=%d\n", randomdelete) varsFile.printf("deletionstep=%d\n", deletionstep) varsFile.printf("segmentlength=%d\n", segmentlength) varsFile.printf("infotriallength=%d\n", infotriallength) varsFile.printf("recording_interval=%d\n", recording_interval) varsFile.printf("t_start=%d\n", recording_start) varsFile.printf("activitytau=%e\n", activitytau) varsFile.printf("activitybeta=%e\n", activitybeta) varsFile.printf("activitygamma=%e\n", activitygamma) varsFile.printf("\n# Cell ID, cell type, activity sensor, target activity, scaling factor, is-dead\n") varsFile.printf("# Recorded every %d ms\n", recording_interval) varsFile.close() header_written = 1 } // Open aux file for append auxFile.aopen() // Record current time auxFile.printf("t = %f\n", t) // Write data to given file for k=0,numcells-1 { id = col.ce.o(k).get_id() act = col.ce.o(k).get_activity() trg = col.ce.o(k).get_target_act() scl = col.ce.o(k).get_scale_factor() type = col.ce.o(k).get_type() dead = col.ce.o(k).get_dead() auxFile.printf("%d,%d,%f,%f,%f,%d\n", id,type,act,trg,scl,dead) //printf("%d,%d,%f,%f,%f,%d\n", id,type,act,trg,scl,dead) } // Close file auxFile.close() // Queue next event cvode.event(t+recording_interval, "write_scaling_data()") } // Callback procedure to start the event queue // NOTE: Only called once, after hoc file initialised and run() has been called proc deletioneventqueue() { // Set up CSTIMs cvode.event(t, "uniquetrialcstim()") // Start alternating 'unique+random' trials cvode.event(scalingstart, "turn_on_scaling()") // Start scaling after initial delay to find activity cvode.event(t + segmentlength, "deletionround()") // Call deletionround() after segmentlength ms cvode.event(t + recording_start, "write_scaling_data()") // Start recording of scalefactors etc } setup() declare("alzfih", new FInitializeHandler("deletioneventqueue()")) // Called as soon as INIT finishes