// $Id: snscode.hoc,v 1.42 2002/04/22 14:17:48 billl Exp $
// handles coding, syn assignment and syn graphics
// load_file("declist.hoc","declist")
load_proc("declist")
objref prelist // list of all presynaptic mechanisms
prelist = new List("PRESYN")
//* CODE GENERATION AND RECOVERY
objref snsgrlist
snsgrlist = new List()
chainlen = 1 // allow the user to change this as needed for synfind or connmat
maxflds = 4 // maximum number of codefields
cdflds = 4 // number of 'code fields'
double cdsep[maxflds+1] // code column separators
// default values see mkfields() call below
// cdsep[0] = 1e9 col 9 - 9
// cdsep[1] = 1e8 col 8 - 7
// cdsep[2] = 1e6 col 6 - 4
// cdsep[3] = 1e3 col 3 - 1
// cdsep[4] = 1e0
// labels can be entered for each of 4 fields, up to 8 labels in each
objref cdlbls[cdflds][8]
for ii=0,cdflds-1 for jj=0,7 cdlbls[ii][jj]=new String("")
//** mkfields() creates up to 4 fields (5 args: # fields, f1,f2,f3,f4)
// eg mkfields(4,1,2,3,3) to recreate the defaults
proc mkfields() { local sum,i
cdflds = $1
cdsep[4] = 1
sum = $5
cdsep[3] = 10 ^ sum
sum = sum + $4
cdsep[2] = 10 ^ sum
sum = sum + $3
cdsep[1] = 10 ^ sum
sum = sum + $2
cdsep[0] = 10 ^ sum
}
mkfields(4,1,2,3,3)
//** mkmkcode(): create the mkcode routine
// no arguments, should follow mkfields()
// not reliable if used under xopen()
proc mkmkcode() { local i
printf("!{!\n")
printf("func mkcode() { \nreturn ")
for (i=1;i<=cdflds;i=i+1) {
printf("$%d*cdsep[%d] + ",i,i+maxflds-cdflds)
}
printf("0 \n}\n")
printf("!}!\n")
}
//** mkcode() creates a code of 9 cols in 4 fields, sized 1,2,3,3
func mkcode() {
// standard 9 cols
// divide into 4 fields of size 1,2,3,3
//col 8 7,6 5,4,3 2,1,0
return $1*cdsep[1] + $2*cdsep[2] + $3*cdsep[3] + $4*cdsep[4]
}
//** cd(i,code) returns field i (1-4) from code
// $1 field number (from 1), $2 code
func cd() { local temp
temp = ($2%cdsep[$1+(maxflds-cdflds)-1]) // remove the left side
return int(temp/cdsep[$1+(maxflds-cdflds)]) // remove the right side
}
//** setcd(i,code,new) replaces field i (1-4) from code with new
// $1 field number (1 offset), $2 code, $3 new value
func setcd() { local temp, old
temp = ($2%cdsep[$1+(maxflds-cdflds)-1]) // remove the left side
old = cdsep[$1+(maxflds-cdflds)]* int(temp/cdsep[$1+(maxflds-cdflds)])
return $2 - old + $3* cdsep[$1+(maxflds-cdflds)]
}
//** prcode(code) prints a code in readable form
// print a code of 9 cols in 4 fields, sized 1,2,3,3
proc prcode() { local i
for (i=(maxflds-cdflds+1);i<maxflds;i=i+1) {
printf("%d,",cd(i,$1))
}
printf("%d\n",cd(maxflds,$1))
}
//** prlbls(code) uses cdlbls to print out strings instead of numbers
// when possible
proc prlbls() { local k,cde
for (k=(maxflds-cdflds+1);k<=maxflds;k=k+1) {
cde = cd(k,$1)
if (k < cdflds && cde < 8) {
if (strcmp(cdlbls[k][cde].s,"") == 0) {
printf("%d,",cde)
} else {
printf("%s,",cdlbls[k][cde].s)
}
} else {
printf("%d,",cde)
}
}
print ""
}
//** chkpre(OBJ,CODE) searches through a syn OBJECT for this CODE
// check whether a code to be included has already been used
// 2 arguments: syn obj, comparison
// returns 1 if found, 0 if not
func chkpre () { local i
for(i=0; i<$o1.nsyn; i=i+1) {
if ($o1.pre(i) == $2){
return 1 } }
return 0
}
//** synfind list1 cd2 fld3 val4 cd5 fld6 val7
// print out codes on all the synapses that criteria
// cd2, cd5 are "pre" or "post" or "code"
// fld3, fld6 is the field
// val4, val7 are the values to look for matching
proc synfind () { local cdx,cdy,i,j,start
if ((cdx = connmat_findstr($s2)) == -1) { printf("unknown string %s",$s2) return }
if ((cdy = connmat_findstr($s5)) == -1) { printf("unknown string %s",$s5) return }
for i=0,$o1.count-1 {
for (j=0;j<$o1.object(i).nsyn-1;j=j+chainlen) {
if (synmatch($o1.object(i),j,cdx,$3,$4,cdy,$6,$7)) {
sprint(temp_string_,"pr = %s.pre(%d)",$o1.object(i),j)
execute(temp_string_)
printf("%s syn# %d: pre==",$o1.object(i),j)
prlbls(pr)
sprint(temp_string_,"pr = %s.post(%d)",$o1.object(i),j)
execute(temp_string_)
printf(" post==")
prlbls(pr)
print ""
}
}
}
}
//*** synmatch obj1 ind2 cf3 fld4 val5 cf6 fld7 val8
// check object fields for matches to values given
func synmatch () { local cdd, cde, i, j
cdd = connmat_newpt($o1,$3,$4,$2,0)
cde = connmat_newpt($o1,$6,$7,$2,0)
if (cdd == $5 && cde == $8) { return 1 } else { return 0 }
}
// parse the strings and return a number telling which it is
// 0:code, 1:pre, 2:post, 3:increment
func connmat_findstr () {
if (strcmp($s1,"code") == 0) { return 0
} else if (strcmp($s1,"pre") == 0) { return 1
} else if (strcmp($s1,"post") == 0) { return 2
} else if (strcmp($s1,"inc") == 0) { return 3
} else { return -1 }
}
// look at return the field needed from the correct word
// word indication as returned by connmat_findstr()
// args: object, word, field, synnum, ind
func connmat_newpt () { local code
if ($2==0) { code = $o1.code($4)
} else if ($2==1) { code = $o1.pre($4)
} else if ($2==2) { code = $o1.post($4)
} else if ($2==3) { return $5 }
if (code >= 0) {
return cd($3,code)
} else {
return -1 // error
}
}
//* FUNCTIONS OPERATING ACROSS ALL PRESYNS
//** checksyns() goes through prelist and prints out divergence value
proc checksyns() { local i
for i=0, prelist.count()-1 {
printf("%d ",prelist.object(i).check())
}
}
//** cleansyns() goes through prelist and collapses the synapse list
proc cleansyns() { local i
for i=0, prelist.count()-1 {
prelist.object(i).clean()
}
}
//** clearsyns() goes through postsyn list and reinitializes everything
proc clearsyns() { local i,j
tmplist.remove_all
tmplist = new List("POSTSYN")
for i=0, tmplist.count()-1 {
for j=0, tmplist.object(i).mech_num - 1 {
if (tmplist.object(i).mech[j].maxsyn > 0) {
tmplist.object(i).mech[j].init_arrays(tmplist.object(i).mech[j].maxsyn)
}
}
}
cleansyns()
}
//* SYNAPSE ASSIGNMENT CODE
// con=absolute convergence number, div=absolute div number
// con = %con * pre
// div * pre = con * post = S (total synapses)
// %div = div/post = S/(pre*post) = con/pre = %con
// div = %con * post
// maxdiv = int((1 + var) * div)
//** ranverge() produces randomized convergence
// used for convergence, rancon (randomized convergence) is given by
// ranverge(%conv,numpre,variance)
// returns a convergence number (number of syns onto a cell)
// that is randomly chosen from (%conv +/- variance)*pre
// if random not wanted just do int(pcon * numpre) instead
func ranverge () { local min, max, ran, pcon, numpre, var
pcon = $1 numpre = $2 var = $3
if (pcon == 1) { return numpre } // fully connected
if (pcon == 0) { return 0 } // no connection
if (var != 0) {
ran = pcon - var + (u_rand() * 2 * var)
} else { ran = pcon } // no variability
return int(ran * numpre + u_rand()) // con * pre or div * post rounded up or down
}
//** pickpre() tries to reduce divergence variance
// pickpre(MECH_NUM,TEMP_PRELIST,MAXDIV)
// may want to create TEMP_PRELIST from PRELIST using sublist()
// maxdiv == -1 means to ignore divergence
// MUST do divvec.resize() and divvec.fill(0) before using
objref divvec,divvec1 // vectors to count how much div is from each nrn
divvec = new Vector(100)
divvec1 = new Vector(100) // a scratch vector
func pickpre () { local ran, maxdiv, maxpre, min, indx, mechnum
mechnum = $1
maxdiv = $3 // max divergence to be allowed
maxpre = $o2.count-1 // number of presyn choices
if (maxdiv == -1) { // just choose one randomly
ran = fran(0,maxpre) // all possible synapses
return ran
}
maxdiv *= mechnum // need space for mult mechs together
// if (divvec.size != prelist.size) {
// printf("Pickpre full ERROR: divvec not sized properly\n") }
min = divvec.min // divvec should start all 0's
if (min >= maxdiv) { // all full up
printf("Pickpre full WARNING: %d %d\n",min,maxdiv)
divvec.printf
}
divvec1.indvwhere(divvec,"==",min) // look for all the smallest to fill up first
ran = fran(0,divvec1.size-1) // pick index of one of these randomly
indx = divvec1.x[ran] // index is the randomly chosen entry in vec of ptrs.
divvec.x[indx] += mechnum // record that this one has been chosen
return indx
}
// check that divergence in individual divvecs is same as divergence in PRESYN structure
// chkdiv(vec,PRELISTmin,PRELISTmax,num_mechs)
// vec is specific divergence vector
// PRELISTmin,max give the entries in prelist to compare
// num gives the number of mechanisms in a single post from this cell
proc chkdiv () { local min,max,num
min = $2 max = $3
if ($o1.size != max-min+1) {
printf("ERROR: divvec size must = # of prelist items: %d %d\n",$o1.size,max-min+1)
return
}
for vtr(&x,$o1) {
if (x != prelist.object(min+i1).nsyn) {
printf("ERROR: %d in %s != nsyn %d\n",x,$o1,prelist.object(min+i1).nsyn)
}
}
}
//* template POSTSYN
proc callback () {}
begintemplate POSTSYN
public mech, mech_num, post
public init_arrays, augment_array, conn
public up
external pickpre, callback
objref mech[1],this,up // to be resized later
//** init() args are syn objects
proc init() {
mech_num = numarg()
objectvar mech[mech_num]
if (mech_num >= 4) { mech[3] = $o4 }
if (mech_num >= 3) { mech[2] = $o3 }
if (mech_num >= 2) { mech[1] = $o2 }
if (mech_num >= 1) { mech[0] = $o1 }
}
//** augment_array() add $1 to current number of synapses
func augment_array() {
num = $1
for k=0,mech_num-1 {
newmax = mech[k].maxsyn + num
mech[k].init_arrays(newmax)
}
return newmax
}
//** init_arrays() initialize all mechs to maxsyn = $1
func init_arrays() {
num = $1
for k=0,mech_num-1 {
mech[k].init_arrays(num)
}
return num
}
//** conn() find some places in a list to connect to
// (list, con, maxdiv, [delay, gmax])
// maxdiv == -1 means to ignore divergence
func conn () {
con = $2 maxdiv = $3
numpre = $o1.count
if (numarg()>3) {delay = $4 gmax = $5 setall=1
} else { setall = 0 }
for j=0,con-1 {
if (con == numpre) { // do all of them in order
rannum = j
} else {
rannum = pickpre(mech_num,$o1,maxdiv)
if (rannum==-1) { printf(": %d/%d done\n",j,con)
return -1 }
}
for k=0,mech_num-1 {
// post, pre, listcnt, syncnt, mechcnt, precnt
mech[k].setlink($o1.object(rannum).link, $o1.object(rannum).nsyn, $o1.object(rannum).maxsyn)
if (setall) {
mech[k].delay(-1,delay) // set most recent (index nsyn-1)
mech[k].gmax(-1,gmax)
} else {
callback(mech[k],k,rannum)
}
}
}
return 0
}
endtemplate POSTSYN