// $Id: snscode.hoc,v 1.28 1995/11/20 02:24:07 billl Exp $
// handles coding, syn assignment and syn graphics
//* CODE GENERATION AND RECOVERY
//** Declarations
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
// use the criterion in s1 to pick out the first syn in list2 and add to list1
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
}
}
//* LISTS
//** Declarations
objref prelist // list of all presynaptic mechanisms
prelist = new List("PRESYN")
objref tmplist
tmplist = new List()
objref sfunc
sfunc = new StringFunctions()
strdef mechnames
//** sublist() places a sublist in LIST0 from LIST1 index BEGIN to END inclusive
proc sublist () { local ii
$o1.remove_all
for ii=$3,$4 {
$o1.append($o2.object(ii))
}
}
//** catlist() concats LIST1 on end of LIST2
proc catlist () { local ii
for ii=0,$o2.count-1 {
$o1.append($o2.object(ii))
}
}
//** mechlist() creates a LIST of all this CELL type's TEMPLATE type
// list, cell, template
// make a list of mechanisms belonging to a certain template
proc mechlist () { local num,ii
// mechnames = "" // not a good storage since runs out of room
if (numarg()==0) { print "mechlist(list, cell, template)" return}
$o1 = new List($s2)
num = $o1.count
for ii=0,num-1 {
sprint(temp_string_,"%s.append(%s.%s)",$o1,$o1.object(ii),$s3)
execute(temp_string_)
// sprint(mechnames,"%s/%d/%s.%s",mechnames,ii,$o1.object(ii),$s3)
}
for (ii=num-1;ii>=0;ii=ii-1) { $o1.remove(ii) }
}
//** lp() loop through a list running command in object's context
// list($o), obj_elem($s), comm($s)
// with 2 args run $o1.object().obj_elem
// with 3 args run comm($o1.object().obj_elem)
proc lp () {
for ii=0,$o1.count-1 {
printf("%s ",$o1.object(ii))
if (numarg()==3) {
sprint(temp_string_,"%s(%s.%s)",$s3,$o1.object(ii),$s2)
} else {
sprint(temp_string_,"%s.%s",$o1.object(ii),$s2)
}
execute(temp_string_)
}
}
//** prlp() loop through a list printing object name and result of command
proc prlp () {
for ii=0,$o1.count-1 {
printf("%s ",$o1.object(ii))
if (numarg()==2) {
sprint(temp_string_,"print %s.%s",$o1.object(ii),$s2)
execute(temp_string_)
} else { print "" }
}
}
//* 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(POSTSYN_MECH,TEMP_PRELIST,MAXDIV)
// like newpre() except that in addition to insuring no repeats
// also tries to even out divergence
// may want to create TEMP_PRELIST from PRELIST using sublist()
// maxdiv == -1 means to ignore divergence
func pickpre () { local ran, maxdiv, maxpre, cnt, ii
maxdiv = $3
maxpre = $o2.count-1
cnt = 0
while (1) {
cnt = cnt+1
ran = fran(0,maxpre) // all possible synapses
if (chkpre($o1,$o2.object(ran).pre)) { // don't allow 2 connects from same place
continue
}
// chance of adding another reduces depending on how close to maxdiv
if ((maxdiv == -1) || ($o2.object(ran).check <= maxdiv && \
fran(0,maxdiv) < (maxdiv - $o2.object(ran).check))) { break }
if (cnt > 3*maxpre) { // enough fruitless searching
for ii=0,$o2.count-1 {
if ($o2.object(ii).check <= maxdiv) {
return ii
}
}
print "ERROR in pickpre(): no more room (maxdiv reached)"
return -1
}
}
return ran // return the index into the cell array
}
//* 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, conv, maxdiv, [delay, gmax])
// maxdiv == -1 means to ignore divergence
proc 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[0],$o1,maxdiv)
if (rannum==-1) { return }
}
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)
}
}
}
}
endtemplate POSTSYN