// $Id: nqs.hoc,v 1.689 2012/10/04 01:41:57 billl Exp $
// primarily edited in nrniv/place
if (!name_declared("VECST_INSTALLED")) {
printf("NQS ERROR: Need vecst.mod nmodl package compiled in special.\n")
quit()
}
if (!VECST_INSTALLED) install_vecst()
if (! name_declared("datestr")) load_file("setup.hoc")
load_file("decvec.hoc")
objref g[10]
gvmarkflag=0
declared("file_len")
strdef execstr,strform
strform="%s "
//* stubs for ancillary programs
double sops[21] // AUGMENT TO ADD NEW OPSYM
declared("whvarg","whkey","varstr","nqsdel","chsel2","grsel2","oform")
proc oformoff () { execute1("func oform(){return NOP}") } // default no operation
proc oform64(){execute1("func oform(){{$o1.vpr(64,1)}return OK}")} // vec.vpr(64)
oformoff()
nqsselcp=1
//* NQS template
// potential to overwrite XO,tmpfile,i1
begintemplate NQS
public cob,out,up // operate on this or out
public s,comment,file,v,m,x,ind,scr,fcd,fcds,fcdo,fcdv,fcdl,sstr // strings and vecs
public objl,verbose,tmplist,vlist,vl,vlc,nval,sval,oval,selcp,rxpstr,slorflag,stub,chunk,rdpiece
public sv,rd,append,pr,pri,prs,zvec,resize,size,fi,sets,set,setcol,setcols,gets,get,fetch,tog
public cp,copy,mo,aind,it,qt,ot,ut,vt,appi,eq,fcdseq,fcdoeq,sort,select,stat,map,apply,applf
public calc,pad,unpad,delect,fill,uniq,gr,clear,strdec,coddec,odec,fdec,vdec
public join,fillin,fillv,otl,selall
public unuselist,useslist,delrow,elimrepeats,grow,shuffle,fewind,listvecs,loose,rdcols,rdcols2
public percl,psel,svsetting,getrow,getcol,resize2,find,family,delcol,keepcols,selone
public sethdrs,gethdrs,version,svvers,i2,ay,svcols,svR,scpflag,unref,refs,qtset,keylook,cpout
public deriv,interval,renamecol,renamecols,info,getsel,tomat,frmat,marksym,vsort,hash,unnan
public cindx,mkind,cindcol,mset,mget,covarc,tomatc,noheader,csel,newval,rddif,rdatf,transpose
objref v[1],s[1],is[4],x,nil,ind,scr[3],fcd,fcds,fcdo,fcdv,fcdl,this,objl
objref cob,out,up,Xo,Yo,oval,tmplist,otl,vlist,vl,vlc,info,cindx
strdef comment,file,sstr,sstr2,sstr3,sstr4,tstr,sval,nqsvers,marksym
double m[1],refs[1]
external readnums,savenums,rdvstr,wrvstr,sfunc,repl_str,repl_mstr,isobj,rdmord,count_substr
external vlk,Union,String,tmpfile,strm,XO,execstr,i1,allocvecs,dealloc,mso,strform,dblform,tabform
external eqobj,isnum,chop,isassigned,whvarg,whkey,sops,batch_flag,g,varstr,gvmarkflag,split
external file_len,nqsdel,chsel2,grsel2,oform,nqsselcp,tmpobj,fln,fln_lnum
//** init()
proc init () { local i,ii,flag,ofl,scnt,na,fl,rdflag
refs=-1 CODTY=10 FUNTY=11 VECTY=12 verbose=1
noheader=nval=fl=scnt=ofl=flag=rdflag=ni=0 // flag set if creating the internal NQS
selcp=nqsselcp
svsetting=4 loose=1e-6
for ii=2,3 is[ii]=new String()
is[3].s="INDEX" is[2].s="SCRATCH"
na=numarg()
for i=1,na scnt+=(argtype(i)==2) // string count
if (na==0) scnt=-1
if (na==1) if (argtype(1)==2) rdflag=1 else if (argtype(1)==1) rdflag=2
if (na>=1) if (argtype(1)==0) {
fl=1 // 1 arg taken care of
if ($1<=-10) {
flag=1 up=$o2 fl=2 ofl=-($1+10)
m=up.m
if (ofl) {
objref v[m]
for ii=0,m-1 v[ii]=new Vector()
} else if (m>0) {
objref v[m],s[m]
for ii=0,m-1 {v[ii]=new Vector() s[ii]=up.s[ii]}
}
fcd=up.fcd
fcds=up.fcds fcdl=up.fcdl fcdo=up.fcdo fcdv=up.fcdv // finish creation of .out here
} else if ($1<0) { // flag to create a large set of vectors with no labels and no .out
fl=2 noheader=ofl=-$1
if (argtype(2)==0) m=$2 else m=$o2.count()
objref v[m]
for ii=0,m-1 v[ii]=new Vector() // no s[ii] strings
if (argtype(2)==1) for ii=0,m-1 v[ii].copy($o2.o(ii))
} else {
m=$1
objref v[m],s[m]
for ii=0,m-1 { v[ii]=new Vector() s[ii]=new String2() }
}
}
if (fl!=1 && na==scnt) { // all strings
fl=2 // all args taken care of
m=na
objref v[m],s[m]
for ii=0,m-1 {i=ii+1 v[ii]=new Vector() s[ii]=new String2($si) }
}
if (fl!=2 && na>=2) if (argtype(2)==0) {
fl==2 // all args taken care of
for ii=0,m-1 v[ii].resize($2)
}
if (fl!=2) { // if first arg is not a string these other can be
if (na>=2) file=$s2
if (na>=3) comment=$s3
if (na>=4) x.x[0]=$4
}
if (!flag) {
// fcd gives field codes according to values used for argtype()
fcds=new List() fcd=new Vector(m) tmplist=new List() vlist=new List()
fcd.resize(m) fcd.fill(0) // field codes to have a field that's string based
}
x=new Vector(m) ind=x.c for ii=0,2 scr[ii]=x.c
scr.resize(0) ind.resize(0)
objl=new List() cob=this
v0sz=slorflag=0
qtset=0
chunk=100
info=new Union()
nqsvers="$Id: nqs.hoc,v 1.689 2012/10/04 01:41:57 billl Exp $" svvers=-1
if (!flag && ofl!=2) {
out=new NQS(-10-ofl,this)
if (rdflag==1) rd($s1)
if (rdflag==2) copy($o1)
}
chk()
}
// deallocate the attached nqs if destroyed
// after build NQS should have external pointer and out.up pointer +/- cob
// NB: 'this' is created and destroyed as needed
proc unref () {
return
// if (isassigned(out)) printf("AA:%d ",$1) else printf("BB:%d ",$1)
if ($1<=refs) { // don't bother if have more than 2 refs or if currently building
if (m>=0 && isassigned(out)) { // only do it on a live master nqs
if ($1<2 || eqobj(cob,out.up)) { // means that only up are left
m=-7 // indicate have started the process so don't reenter here
printf("Entering destructor for %s: %d %d %s %s %s\n",out.up,$1,refs,cob,out,out.up)
out.unref(-1) // take care of out first
}
}
}
if ($1==-1) { // for .out
cob=nil
up=nil
} else if (m==-7) { // should only be done once
m= -8
// printf("Removal of %s on call %d\n",out.up,$1)
if (isassigned(fcdo)) fcdo.remove_all
if (isassigned(fcds)) fcds.remove_all
if (isassigned(fcdv)) fcdv.resize(0)
cob=nil
up=nil
}
}
//** make sure there are no inconsistencies -- also set vl
func chk () { local ii,jj,ret
ret=1
if (out!=nil && !noheader) {
for ii=0,m-2 for jj=ii+1,m-1 {
if (sfunc.len(s[ii].s)>0 && strcmp(s[ii].s,s[jj].s)==0) {
printf("NQS:chk ERRA: %s col: %s(%d) %s(%d) with same name\n",this,s[ii].s,ii,s[jj].s,jj)
ret=0
}
}
}
listvecs(vl)
return ret
}
//** tog() toggle flag that determines whether actions are on out or this
func tog () { local ret
if (eqobj(cob,out)) ret=20 else ret=10 // report old value
if (numarg()==0) {
if (eqobj(cob,out)) { cob=this if (verbose) print "Operate on full db"
} else { cob=out if (verbose) print "Operate on output of select"
}
} else if (numarg()==1) {
if (argtype(1)==0) {
if ($1>=10) { // set
if ($1==10) cob=this else if ($1==20) cob=out else printf("tog ERRA:%d\n",$1)
} else { // just give information
if (eqobj(cob,out)) { print "Using output db"
} else { print "Using full db" }
}
} else if (argtype(1)==2) { // out,output,selected to choose these
if (strm($s1,"[Oo][Uu][Tt]") || strm($s1,"[Ss][Ee][Ll]")) {
cob=out
} else {
cob=this
}
}
}
return ret
}
//** sethdrs() set the column names to given args
// sethdrs(#,"NAME") sethdrs("NAME1","NAME2",...) sethdrs(nq) -- copy from nq
proc sethdrs () { local i,nm
nm=numarg()
// out.s should always be a pointer to s but early on was keeping different copies:
if (! eqobj(s,out.s)) printf("sets INTERRA\n")
if (nm==2 && argtype(1)==0) {
s[$1].s=$s2
} else if (nm==1) {
if ($o1.m!=m) resize($o1.m)
for i=0,m-1 s[i].s=$o1.s[i].s
} else {
if (nm>m) {
if (batch_flag) {
printf("NQS sets WARNING resized table from %d to %d\n",m,nm)
} else if (! boolean_dialog("Resize TABLE?","YES","NO")) return
printf("resizing TABLE: %d -> %d\n",m,nm) resize(nm)
}
for i=1,nm { s[i-1].s=$si }
}
}
// gethdrs() print the strings
proc gets () { printf("gets() changed to gethdrs()\n") }
proc gethdrs () { local ii,jj,kk,mm localobj o
if (numarg()==1) {
if ($1==-1) { // set the strings
if (!batch_flag && sfunc.len(s[0].s)!=0) {
printf("Overwrite headers for %s? (y/n) ",this)
getstr(tstr) chop(tstr)
if (strcmp(tstr,"y")!=0) return
}
o=new String("%s%c")
for ii=0,m-1 {
jj=ii%26 kk=int(ii/26)+1
for mm=1,kk sprint(s[ii].s,o.s,s[ii].s,65+jj)
}
} else if ($1==1) { // show the types of fields
for ii=0,m-1 printf("%s(%d) ",s[ii].s,fcd.x[ii])
} else if ($1==2) { // just the names
for ii=0,m-1 printf("%s ",s[ii].s)
}
} else {
for ii=0,m-1 printf("%s(%d) ",s[ii].s,ii) // field numbers
}
}
//* selone(COL,VAL[,FLAG]) -- uses vec.slone when just working with one col and one value
func selone () { local val,niflag
if (numarg()==3) niflag=$3 else niflag=0 // use if searching repeatedly through same vec
tog("DB") // start at full db
if (argtype(1)==2) fl=fi($s1) else fl=$1
if (fl==-1) return
val=$2
// if (!v[fl].ismono) {printf("NQS selone: must sort on %s before using\n",s[fl].s) return -1}
if (niflag) ni=ind.slone(v[fl],val,ni) else ni=ind.slone(v[fl],val)
if (selcp) {
if (ind.size==0) {
if (verbose) printf("None selected\n")
} else {
out.ind.copy(ind)
aind()
cob=out
}
} else cob=this
return ind.size
}
//* ay() is an n-dim associative array with p return values
// emulate a high-dim sparse array with optional string args, eg
// nq.ay("SU","IN",7,2,12).x // like nq_array["SU"]["IN"][7][2][12]
// an associative array could do same with non-numeric indices
// here if we have m cols can use any n of them as indices and rest are return values up to
// what a Union() can hold (2 strings, 2 objs, 2 doubles)
// if want to ignore one index can use OK as a globbing value
// for SET use an explicit set aa[5][4][7][2][12]=17 -> nq.ay(5,4,7,2,12,SET,17)
// select based on first n cols and always using EQU or SEQ
// gives more feel of an array -- assumes columns are IND0,IND1,...,VAL
// keys are SET to begin setting values, and OK to leave a value as is
// noninteger must be a set value
// eg XO=ncq.ay(SU,SU,AM,INC,SET,OK,List[35])
// alternate use with specific labels for things to be set eg
// eg XO=ncq.ay(SU,SU,AM,SET,"del",2.2,"wt")
obfunc ay () { local a,b,i,j,jo,k,na,flag,done,ix,nx,sx,ox,fl localobj key,arg,o
if (numarg()==0) {
printf("ay(I0,I1 ...[SET,V1,V2 ...])\n") return o }
tog("DB") // start at full db
a=allocvecs(key,arg)
o=new Union() o.err=1 // assume .err set to return errors
na=numarg()
vlist.remove_all
ind.resize(v.size)
if (argtype(1)==1) for ii=0,$o1.size-1 {
key.append(EQU) arg.append($o1.x[ii],0) vlist.append(v[ii])
flag=0 j=b=$o1.size
if (numarg()>1) if ($2==SET) {i=3 flag=1}
} else {
for ({i=1 flag=0 done=0} ; i<=na && !flag; {i+=1 done=0}) {
if (argtype(i)==2) {
if (fi($si,"NOERR")!=-1) break else if (fcd.x[i-1]!=2) {
printf("ay ERRA: %d %d\n",fcd.x[i-1],argtype(i)) dealloc(a) return o
}
for (j=0;j<fcds.count && !done;j+=1) if (strcmp(fcds.o(j).s,$si)==0) {
key.append(EQU) arg.append(j,0) vlist.append(v[i-1]) done=1
}
if (!done) {printf("%s ay ERRE: %s not found in col %s\n",this,$si,s[i-1].s)
dealloc(a) return o }
} else if (argtype(i)==0) {
if ($i==GET) { flag=2 // this is a value to start retrieval
} else if ($i==SET) { flag=1 // this is a value to set
} else if ($i!=OK) { // ignore an OK
key.append(EQU) arg.append($i,0) vlist.append(v[i-1])
}
}
}
b=i-1 // will begin again here -- these are v[] indices hence 0- statt 1-offset
j=i-2 // have also had a SET arg to go behind
}
ind.slct(key,arg,vlist)
if (ind.size>1) printf("%s ay WARNING: mult rows %d (using %d)\n",this,ind.size,ind.x[0])
if (ind.size==0) { // printf("%s ay ERRBB: none selected\n",this)
dealloc(a) return o }
ix=ind.x[0] // just getting the first row of this
if (i==na && argtype(i)==2) if ((fl=fi($si,"NOERR"))!=-1) { // return just 1 with col label
j=getval(fl,v[fl].x[ix],ix)
if (j==0) o.x=nval else if (j==1) o.o=oval else if (j==2) o.s=sval
dealloc(a)
o.err=0
return o
}
for (;i<=na && flag==1;{i+=1 j+=1 jo=0}) { // set using the rest of the args
if (argtype(i)==0) if ($i==OK) continue // don't set this one
if (argtype(i)==2) {
if (strcmp($si,"")==0) continue // don't set this one
if ((k=fi($si,"NOERR"))!=-1) {jo=j j=k i+=1}
}
if (argtype(i)!=fcd.x[j]) {
printf("%s ay ERRC: %d %d %d\n",this,i,fcd.x[j],argtype(i)) dealloc(a) return o }
if (argtype(i)==0) { v[j].x[ix]=$i
} else if (argtype(i)==1) { set(j,ix,$oi) print $oi,ix
} else if (argtype(i)==2) { set(j,ix,$si)
} else {printf("%s ay ERRD: set %d not implemented\n",this,argtype(i)) dealloc(a) return o}
if (jo) j-=1 // back up: perhaps can but would be a bad idea to mix setting stuff
}
nx=sx=ox=-1
if (flag==2) {i=b if ((b=fi($si,"NOERR"))==-1) {
printf("nqs:ay() GET ERR %s not found\n",$si) return o }}
for (i=b;i<m;i+=1) { // return values -- get 10 of each
j=getval(i,v[i].x[ix],ix)
if (j==0) {
nx+=1
if (nx>=10) continue
o.set(s[i].s,nval)
} else if (j==1 || j==2) {
ox+=1 // string is handled as String obj
if (ox>=10) continue
if (j==2) o.set(s[i].s,sval) else o.set(s[i].s,oval)
}
}
dealloc(a)
o.err=0
return o
}
//* select() -- based loosely on SQL select
func select () { local ii,i,tmp,tmp1,ret,isv,key,arg,vc,selcpsav,savind,union,not,rxpflg localobj o
if (numarg()==0) { out.cp(this,2) cob=out return v.size }
tog("DB") // start at full db
if (size(1)==-1) { printf("%s:select ERR0: cols not all same size\n",this) return -1 }
// key holds OPs; arg holds ARGs; vc holds COL NAMEs
key=arg=vc=allocvecs(3) arg+=1 vc+=2 // key is an operator, arg is args, vc is col#
selcpsav=selcp i=1 not=rxpflg=union=savind=0
tmplist.remove_all vlist.remove_all
if (argtype(i)==0) if ($1==-1) {selcp=0 i+=1} // else is a number identifying a vector
if (argtype(i)==2) { // check first string for &&, ||, !
if (strcmp($si,"&&")==0) { savind=1 union=0 i+=1
} else if (strcmp($si,"||")==0) { savind=1 union=1 i+=1
} else if (strcmp($si,"!")==0) { savind=0 not=1 i+=1
} else if (strcmp($si,"&&!")==0) {savind=1 not=1 i+=1
} else if (strcmp($si,"||!")==0) {savind=1 union=1 not=1 i+=1 }
} else if (argtype(i)==1) { i+=1
if (argtype(i)==1 && argtype(i+1)==1) { // 3 vectors in a row are preset info for slct()
if (numarg()!=3) { printf("%s:select ERR0: 3 vecs should be mso[key],mso[arg],cols\n",this)
dealloc(key) return -1 }
if ($o1.size!=$o3.size || $o1.size*2!=$o2.size) {
printf("%s:select ERR0c: size problem %d %d %d\n",this,$o1.size,$o2.size,$o3.size)
dealloc(key) return -1 }
i=4 // have sucked up all the args
mso[key].copy($o1) mso[arg].copy($o2)
for ii=0,$o3.size-1 vlist.append(v[$o3.x[ii]])
} else if (isobj($o1,"Vector")) { ind.copy($o1) savind=1 union=0 // assume &&
} else {
printf("%s:select ERR0a: first vec obj should be ind vector\n",this) dealloc(key) return -1 }
}
if (savind) scr.copy(ind) else scr.resize(0)
while (i<=numarg()) {
if (argtype(i)==2) {
if (strcmp($si,"IND_")==0) {
if ((vn=fi($si,"NOERR"))!=-3) {
printf("NQS:select() WARNING: IND_ is a reserved word: ?%s\n",s[vn].s) }
vn=-1e9 scr[1].indgen(0,v.size-1,1) tmplist.prepend(scr[1])
} else if ((vn=fi($si))<0) { dealloc(key) return -1 }
sstr=$si // save for join: use with "NAME",EQW,OTHER_NQS
} else if (argtype(i)==0) { vn=$i // can avoid repeated string search
if (vn<0 || vn>=m) {
printf("%s:select ERR0b: can't ident arg %d: %d\n",this,i,vn) dealloc(key) return -1}
if (s[vn]!=nil) sstr=s[vn].s else sstr="UNDEFINED"
} else {printf("%s:select ERR1: arg %d should be col name or num\n",this,i) dealloc(key) return -1}
if (vn>=0) if (fcd.x[vn]==1) {
if (oform(fcdo.o(v[vn].x[0]))!=NOP) { // look at obj list
scr[1].resize(0)
for ii=0,v[vn].size-1 scr[1].append(oform(fcdo.o(v[vn].x[ii])))
vn=-1e9 tmplist.prepend(scr[1])
} else {
printf("NQS:select WARNING selecting on indices in an obj column: %d (?oform)\n",vn)
}
}
mso[vc].append(vn) i+=1
if (argtype(i)==0) {
if ((isv=isvarg($i))!=-1) {
lk=$i
} else { // arg2 is a regular number use "~"
mso[key].append(IBI) // approximately equal -- generate a range
tmp=$i-loose tmp1=$i+loose
if (tmp<tmp1) mso[arg].append(tmp,tmp1) else mso[arg].append(tmp1,tmp)
i+=1
continue
}
} else if (argtype(i)==2) { isv=isvarg(lk=whvarg($si))
if (isv==-1) {
if (strcmp($si,"==")==0 || strcmp($si,"~")==0) {
mso[key].append(IBI) // approximately equal -- generate a range
i+=1
tmp=$i-loose tmp1=$i+loose
if (tmp<tmp1) mso[arg].append(tmp,tmp1) else mso[arg].append(tmp1,tmp)
i+=1
continue
} else {
printf("%s:select ERR1a: operator %s not recognized\n",this,$si) dealloc(key) return -1
}
}
} else {
printf("%s:select ERR2: arg %d/%d should be symbolic (eg GTE, EQU ...) or string (eg '[)','<=') op: %d\n",this,i,numarg(),argtype(i))
dealloc(key) return -1
}
mso[key].append(lk) i+=1
// pick up ARGS
for ii=0,isv-1 {
if (argtype(i)==0) {
if (lk==EQV) {
if ($i<0 || $i>=m) printf("ERRQ\n") else {
mso[arg].append(0)
mso[vc].append($i)
}
} else mso[arg].append($i)
i+=1
} else if (argtype(i)==2) {
if (lk==EQV) { // look for a column id
vn=fi($si) // OPSYM exception
if (vn==-1) { printf("%s:select ERR2a EQV but what col?\n",this) dealloc(key) return -1 }
mso[arg].append(0)
mso[vc].append(vn) i+=1
} else if (lk==SEQ) {
mso[key].x[mso[key].size-1]=EQU
if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
mso[arg].append(ret=finval(vn,argtype(i),lk)) i+=1
} else if (lk==RXP) {
mso[key].x[mso[key].size-1]=EQW
mso[arg].append(0)
if (argtype(i)!=2) {printf("%s:select ERR2a1\n",this) dealloc(key) return -1}
if (rxpflg==1) {printf("%s:select ERR2a2: RXP twice\n",this) dealloc(key) return -1}
ret=tmplist.prepend(scr[2])
if (rxpstr(vn,$si,scr[2])==0) {
printf("%s:select WARNING: No RXP matches for %s\n",this,$si) }
mso[vc].append(-1e9) i+=1
} else {printf("%s:select ERR2b string arg needs EQV,SEQ or RXP?\n",this)
dealloc(key) return -1}
} else if (argtype(i)==1) {
if (lk>=EQW && lk<=EQY) { // pick up a vector
if (isobj($oi,"Vector")) {
if ($oi.size==0) {printf("%s:select ERR2a3: EQ[WXY] with empty vec %s\n",this,$oi)
dealloc(key) return -1}
mso[arg].append(0)
mso[vc].append(-i) i+=1
} else if (isobj($oi,"NQS")) {
mso[arg].append(0)
if ((tmp=$oi.fi(sstr,"NOERR"))!=-1) { // JOIN with output from other nqs
tmplist.prepend($oi.out.v[tmp])
} else {
o=$oi i+=1
if ((tmp=o.fi($si))==-1){printf("%s:select ERR2c: can't find %s in %s?\n",this,$si,o)
dealloc(key) return -1 }
tmplist.prepend(o.out.v[tmp])
}
mso[vc].append(-1e9) i+=1
} else { printf("%s:select ERR2c1: EQ[WXY] needs Vec or NQS not %s?\n",this,$oi)
dealloc(key) return -1
}
} else { printf("%s:select ERR2d only EQ[WXY] takes obj arg: %d:%d?\n",this,i,argtype(i))
dealloc(key) return -1}
} else {
whkey(lk,sstr) printf("%s:select ERR3 arg %d should be arg for %s",this,i,sstr)
dealloc(key) return -1
}
}
// args in wrong order - swap
if (isv==2) if (mso[arg].x[mso[arg].size-2]>mso[arg].x[mso[arg].size-1]) {
tmp=mso[arg].x[mso[arg].size-2]
mso[arg].x[mso[arg].size-2]=mso[arg].x[mso[arg].size-1]
mso[arg].x[mso[arg].size-1]=tmp
}
// pad so every OP sees 2 ARGS
for ii=0,2-isv-1 { mso[arg].append(0) }
}
ind.resize(v.size)
for ii=0,mso[vc].size-1 { vn=mso[vc].x[ii]
if (vn==-1e9) { // code for EQW case with NQS arg
vlist.append(tmplist.object(tmplist.count-1))
tmplist.remove(tmplist.count-1) // pop
} else if (vn<0) { i=-vn // code for EQV case where vector is in the arg list
vlist.append($oi)
} else vlist.append(v[vn])
}
if (tmplist.count!=0) { printf("NQS:select ERR5 %s.tmplist not empty\n",this) return -1 }
if (slorflag) { ind.slor(mso[key],mso[arg],vlist)
} else { ind.slct(mso[key],mso[arg],vlist) }
if (verbose==2) keylook(key) // look at the keys
if (not==1) complement() // ind->!ind
if (savind) {
if (union==1) {
scr.append(ind) scr.sort ind.resize(scr.size+ind.size)
ind.redundout(scr)
} else {
mso[key].resize(scr.size+ind.size)
mso[key].insct(scr,ind) ind.copy(mso[key]) }
}
ret=ind.size
if (selcp) {
out.ind.copy(ind)
if (ind.size==0) {
if (verbose) printf("None selected\n")
} else {
aind()
cob=out
}
} else cob=this
dealloc(key)
selcp=selcpsav
slorflag=0
return ret
}
//** keylook()
proc keylook () { local key,arg,vc,ii
if (numarg()==0) key=0 else key=$1
arg=key+1 vc=key+2
printf("slct(keys,args,cols)\n")
for ii=0,mso[key].size-1 {
whkey(mso[key].x[ii],tstr)
for jj=0,m-1 if (eqobj(v[jj],vlist.o(ii))) break
if (jj==m) jj=-1
printf("KEY: %s; ARGS: %g %g; COL: %d (%s)\n",\
tstr,mso[arg].x[2*ii],mso[arg].x[2*ii+1],jj,vlist.o(ii))
} // vlk(mso[key]) vlk(mso[arg])
}
//** selall()
proc selall () { local ii
if (numarg()==2) {
for ii=0,m-1 out.v[ii].where(v[ii],$s1,$2)
} else {
for ii=0,m-1 out.v[ii].where(v[ii],$s1,$2,$3)
}
tog("SEL")
}
// csel() puts col#s in ind
// csel(colname) select by column header
// csel("OP",arg1[,arg2]) runs oform() on each col then runs OP() on result
// eg with oform(){return $o1.count(0)} then csel("==",3) finds cols with 3 zeros
func csel () { local a,ii localobj v1
a=allocvecs(v1,m)
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (numarg()==1) {
for ii=0,m-1 if (strm(s[ii].s,$s1)) v1.append(ii)
ind.copy(v1)
} else {
for ii=0,m-1 v1.append(oform(cob.v[ii]))
if (numarg()==2) { ind.indvwhere(v1,$s1,$2)
} else { ind.indvwhere(v1,$s1,$2,$3) }
}
dealloc(a)
return ind.size
}
//** complement() ind -> !ind
proc complement () { local a,b
a=b=allocvecs(2) b+=1
mso[a].indgen(0,size(1)-1,1)
mso[b].resize(mso[a].size)
mso[b].cull(mso[a],ind)
ind.copy(mso[b])
dealloc(a)
}
//** delect([NQS])
// move the selected rows from the out db [or other] back to the main db
// the assumption is that you have operated on some of the fields and now want to
// put the rows back
// ind must not have been altered since it will be used to replace the items
func delect () { local beg,ii,flag
scr.resize(v.size)
if (numarg()==1) flag=1 else flag=0
if (flag) {
if (m!=$o1.m){
printf("NQS:delect ERRa m mismatch: %s:%d vs %s:%d\n",this,m,$o1,$o1.m) return -1 }
ind.copy($o1.ind)
} else if (out.ind.size==0) { return 0
} else if (!out.ind.eq(ind) || ind.size!=out.v.size) {
printf("NQS:delect ERR ind size mismatch\n")
return -1
}
for (beg=0;beg<m;beg+=50) { // sindx() can only handle vecst.mod:VRRY vecs at a time
tmplist.remove_all vlist.remove_all
for ii=beg,beg+49 if (ii<m) tmplist.append(v[ii])
for ii=beg,beg+49 if (ii<m) if (flag) {
vlist.append($o1.v[ii])
} else {
vlist.append(out.v[ii])
}
ind.sindx(tmplist,vlist)
}
cob=this
return ind.size
}
//** isvarg() returns number of args an op takes or -1 if not symbolic OP
func isvarg () { local m,op // ADD NEW OPSYM CHECK
op=$1
for m=0,5 if (op<=EBE*(m+1) && op>=ALL*(m+1)) { op/=(m+1) break } // m is is field key 1-5
if (op<ALL) return -1 else if (op<GTH) return 0 else if (op<IBE) { return 1
} else if (op<=EBE) return 2 else return -1
}
//** fi(STR[,XO]) find the index for a particular string, can set a objref
// fi(STR,INDEX) return INDEXed value from that vector
// fi(STR,"NOERR") suppress error message
// fi(STR,"EXACT") string match
// fi(STR,"ALL") return vector of all indices that match regexp
func fi () { local num,flag,ii,ret,err,ext
if (refs==-1) if (isassigned(out)) { // calculate refs
// refs=sfunc.references(this,1)-1 // make sure 'this' is turned on
// printf("%d refs\n",refs)
}
ext=noerr=err=num=flag=all=0
if (numarg()>=2) if (argtype(2)==2) {
if (strcmp($s2,"NOERR")==0) noerr=1 // use "NOERR" string
if (strcmp($s2,"EXACT")==0) ext=1 // string match statt regexp
if (strcmp($s2,"ALL")==0) {all=1 $o3.resize(0)} // all regexp matches
}
for ii=0,m-1 if (strcmp(s[ii].s,$s1)==0) {flag=1 ret=ii break} // exact match
if (ext) if (flag) return ret else return -1
if (strcmp($s1,"SCR_")==0) {flag=1 ret=-2}
if (strcmp($s1,"IND_")==0) {flag=1 ret=-3}
if (!flag) for ii=0,m-1 { // make sure $s1 could be a regexp to avoid regexp error
if (sfunc.len($s1)<sfunc.len(s[ii].s) && !strm($s1,"[()]")) if (strm(s[ii].s,$s1)) {
if (num>=1) {
if (all) $o3.append(ii) else {
err=1
printf("%s fi ERR: regexp matches more than once: %d %s\n",this,ii,s[ii].s)
}
} else {
if (all) $o3.append(ii)
num+=1 ret=ii flag=1
}
}
}
if (err) printf("NQS WARNING; ambiguous regexp; fi() returning pointer for: %d %s\n",ret,s[ret].s)
if (flag) {
if (numarg()==2 && noerr==0) {
if (argtype(2)==1) {
if (ret==-2) $o2=scr else if (ret==-3) {printf("%s:fi ERRa copy what?\n",this) return ret
} else $o2=v[ret]
} else if (argtype(2)==0) {
if ($2<0 || $2>=v[ret].size) {
printf("%s:fi ERR index out of bounds: %d %d\n",this,$2,v[ret].size)
return -1
}
if (ret==-2) ret=scr.x[$2] else if (ret==-3) {printf("NQS:fi ERRb what?\n") return ret
} else ret=v[ret].x[$2]
} else { printf("%s:fi WARNING 2nd arg ignored\n",this) }
}
return ret
} else {
if (!noerr) printf("%s.fi() ERR '%s' not found\n",this,$s1)
return -1
}
}
//** find(STR) find the vector associated with a COL label
obfunc find () { local fl
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
fl=fi($s1)
if (fl==-2) { return scr
} else if (fl==-3) { return ind
} else return cob.v[fl]
}
//** mkind(COL) sort by COL and then use mkind to put index of a single col in cindx vector
obfunc mkind () { local fl
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (cindx==nil) cindx=new Vector(1e3)
if (argtype(1)==0) fl=$1 else fl=fi($s1)
cindcol=fl
sort(fl)
v[fl].mkind(cindx)
if (argtype(2)==1) $o2.copy(cindx)
return cindx
}
//** set("name",IND,VAL)
proc set () { local fl,ix,sel
sel=0
if (eqojt(cob,out)) { sel=1
if (verbose) printf("NQS set() WARNING: setting value in Selected db\n") }
if (argtype(1)==2) fl=fi($s1) else fl=$1
ix=$2
if (fl==-1) return
if (ix<0) ix=cob.v[fl].size+ix
// 2 LINE 'SET' MACRO
if (ix> cob.v[fl].size) { // nonexistent row
printf("%s set ERRA: col %s size %d<%d\n",this,s[fl].s,v[fl].size,ix) return
} else if (ix==cob.v[fl].size) { // single col expansion
if (sel) {printf("%s set() ERR: can't expand Selected db\n",this) return}
cob.v[fl].resize(ix+1)
}
if (argtype(3)==0) { cob.v[fl].x[ix]=$3
} else {
if (argtype(3)==1) oval=$o3 else if (argtype(3)==2) sval=$s3
cob.v[fl].x[ix]=newval(argtype(3),fl)
}
}
//** sets(IND,COLA,VAL[,COLB,VAL,...])
proc sets () { local fl,ix,i,sel,sz
sel=0 ix=$1
if (eqojt(cob,out)) { sel=1
if (verbose) printf("NQS set() WARNING: setting value in Selected db\n") }
if (ix>=cob.v.size){
printf("NQS sets ERRA: OOB %s: %d (size %d)\n",this,v[0].size,cob.v.size) return }
if (ix<0) ix=cob.v.size+ix
for i=2,numarg() {
if (argtype(i)==2) fl=fi($si) else fl=$i
if (fl==-1) return
i+=1
if (argtype(i)==0) { cob.v[fl].x[ix]=$i // shortcut
} else {
if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
cob.v[fl].x[ix]=newval(argtype(i),fl)
}
}
}
//** setcol("name",VEC)
// setcol(num,VEC)
// setcol(num,"name",VEC)
// setcol(num,"name",VEC,flag) // with flag==1 use pointer to vec instead of copying
scpflag=0
proc setcol () { local fl,flag localobj vo
if (eqobj(cob,out) && verbose) {
printf("%s setcol() ERR: attempting to set column in Selected db\n",this)
return }
if (argtype(1)==2) fl=fi($s1) else fl=$1
if (fl==-1) return
if (v[fl].size!=0) {
sprint(sstr,"WARNING %s col not empty (size %d)",s[fl].s,v[fl].size)
if (boolean_dialog(sstr,"Clear col","Cancel")) { v[fl].resize(0) } else {
printf("%s (%s) setcol() canceled\n",this,s[fl].s) return
}}
if (argtype(2)==2) { s[fl].s=$s2
} else if (argtype(2)==1) {
if (scpflag) v[fl].copy($o2) else v[fl]=$o2
return
} else { sprint(tstr,"%d",$2) s[fl].s=tstr }
if (numarg()>=3) vo=$o3
if (numarg()>=4) flag=$4 else flag=0
if (!flag || scpflag) v[fl].copy(vo) else v[fl]=vo
chk()
}
//** setcols(VEC1,VEC2,...) -- does either pointer or copy depending on scpflag
// setcols(LIST) -- does either pointer or copy depending on scpflag
// see also resize("NAME",vec, ...) for similar functionality
proc setcols () { local i,na,flag,sz
sz=na=numarg() flag=0
if (na==0) { scpflag=1-scpflag
if (scpflag) printf("setcols() will copy vecs\n") else {
printf("setcols() will use vec pointers\n") }
return
}
if (na==1 && isobj($o1,"List")) {flag=1 sz=$o1.count}
if (m==0) resize(sz)
if (eqobj(cob,out) && verbose) {
printf("%s setcols() ERR: attempting to set column in Selected db\n",this)
return }
if (!flag && na!=m) {
printf("%s setcols() ERR: need %d not %d args\n",this,m,na)
return }
if (flag) {
if (scpflag) for i=0,m-1 v[i].copy($o1.o(i)) else for i=0,m-1 v[i]=$o1.o(i)
} else if (scpflag) for i=1,m v[i-1].copy($oi) else for i=1,m v[i-1]=$oi
chk()
}
//** newval(typ,col#) -- check if a value is already on the list and if not put it there
// usuall preceded by eg:
// if (argtype(i)==0) nval=$i else if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
// NB: makes a copy of a Vector or an NQS so DON'T do eg nq.append(new Vector())
func newval () { local ret,typ,ty,fl,ii localobj o
typ=$1 fl=$2 ty=fcd.x[fl] // arg type may not be same as field type
if (ty==typ||ty==-1||(ty==FUNTY&&typ==2)||(ty==VECTY&&typ==1)) { // OK
} else { printf("nqs::newval() ERRa %d statt %d\n",typ,ty) return ERR }
if (typ==0 || ty==-1) {
return nval
} else if (ty==1) { // object handling
if (! isassigned(oval)) return -1
if (isojt(oval,v)) { o=new Vector(oval.size) o.copy(oval)
} else if (isojt(oval,this)) { o=new NQS() o.cp(oval)
} else {
for (ii=0;ii<fcdo.count;ii+=1) if (eqojt(fcdo.object(ii),oval)) { // already on list?
printf("nqs %s WARNING: 2nd pointer to same %s on fcdo\n",this,oval)
return ii
}
o=oval
}
return fcdo.append(o)-1
} else if (ty==FUNTY) { // method handling
for ({ii=0 ret=-1};ii<fcds.count;ii+=1) {
if (strcmp(fcds.object(ii).s,sval)==0) {ret=ii break}
}
if (ret==-1) ret=fcds.append(new String(sval))-1
o=new Union(ret) // .x is pointer to the string
return fcdo.append(o)-1
} else if (ty==VECTY) { // append to a vector
if (!isojt(oval,v)) { printf("nqs:newval ERRB -- put vectors in vdec col\n") return ERR }
ret=fcdv.size()
fcdv.append(oval)
return ret
} else if (ty==2) { // string handling
for (ii=0;ii<fcds.count;ii+=1) {
Xo=fcds.object(ii)
if (strcmp(Xo.s,sval)==0) return ii
}
return fcds.append(new String(sval))-1
}
}
//*** finval(col#,type,OP) find the location on list for an object or string
func finval () { local fl,typ,op,ii,ret
fl=$1 typ=$2 op=$3 ret=-1
if (fcd.x[fl]!=typ) { // doesn't handle fcd.x[]==-1
printf("nqs::finval ERRa type mismatch; %d %d\n",fcd.x[fl],typ) return ERR }
for ii=0,fcds.count-1 { Xo=fcds.object(ii)
if (typ==2) {
if (strcmp(Xo.s,sval)==0) return ii
} else {}
}
// if (ret==-1) printf("nqs::finval WARNING %s not found in string or object list\n",sval)
return ret
}
//*** rxpstr(col#,vec) find the location on list for an object
func rxpstr () { local fl
fl=$1 $o3.resize(0)
if (fcd.x[fl]!=2) {
printf("nqs::rxpstr ERRa type mismatch; %d %d\n",fcd.x[fl],2) return -1 }
for ii=0,fcds.count-1 if (strm(fcds.object(ii).s,$s2)) $o3.append(ii)
return $o3.size
}
//*** getval(col#,index) return type and value in nval,oval,sval as appropriate
// usually followed by eg
// if (typ==0) ... nval else if (typ==1) ... oval else if (typ==2) ... sval
func getval () { local typ,n,flag,fl,ix,ii,ed,nacc
fl=$1 ix=$2 flag=0
typ=fcd.x[fl] // argtype
if (typ==0) {
nval=ix
} else if (typ==CODTY) {
if (numarg()==3) nval=uncodf($3,ix) else {scr.resize(5) scr.uncode(ix)}
} else if (typ==VECTY) {
if (ix>fcdv.size-1) { printf("nqs::getval() ERR fcdv index OOB %d, %d\n",ix,fcdv.size)
return ERR
} else if (ix<0) { printf("nqs::getval() WARNING empty VECTY ptr\n\t") sval="nil" typ=2
} else {
nacc=$3 // direct index only needed here
if (nacc+1<cob.v[fl].size) ed=cob.v[fl].x[nacc+1]-1 else ed=fcdv.size-1
oval = fcdv.c(ix,ed)
}
} else if (typ==1) { // object handling
if (ix>fcdo.count-1) {
printf("nqs::getval() ERR fcdo index OOB %d, %d\n",ix,fcdo.count) return ERR
} else if (ix<0) {
// printf("nqs::getval() WARNING empty obj ptr\n\t")
sval="nil"
typ=2
} else oval = fcdo.object(ix)
} else if (typ==2) { // string handling
if (ix==-1) {
sval="NULL"
} else if (ix<0 || ix>fcds.count-1) {
printf("nqs::getval() ERR index OOB %d, %d\n",ix,fcds.count) return ERR
} else sval=fcds.object(ix).s
} else if (typ==-1) { // string from external list
if (fcdl.count<=fl) {printf("%s getval ERRa\n",this) return -1}
if (! isobj(fcdl.object(fl),"List")) {printf("%s getval ERRb\n",this) return -1}
if (fcdl.object(fl).count<=ix) {printf("%s getval ERRc\n",this) return -1}
if (ix==-1) sval="XX" else {
if (!isobj(fcdl.object(fl).object(ix),"String")){printf("%s getval ERRd\n",this) return -1}
sval=fcdl.object(fl).object(ix).s
}
}
return typ
}
//*** useslist() connects a list of strings to fcdl to use when printing
// fcdl: list of lists to make it easy to attach lists from outside
proc useslist () { local fl,ii
if (argtype(1)==2) fl=fi($s1) else fl=$1
if (fl==-1) return
if (! isobj(fcdl,"List")) {fcdl=new List() out.fcdl=fcdl}
if (fcdl.count!=m) for ii=fcdl.count,m-1 fcdl.append(fcdl) // use fcdl as placeholder
fcdl.remove(fl) fcdl.insrt(fl,$o2) // replace:fcdl.object(fl)=$o2
fcd.x[fl]=-1
}
//*** unuselist() connects a list of strings to fcdl to use when printing
// fcdl: list of lists to make it easy to attach lists from outside
proc unuselist () { local fl,ii
if (argtype(1)==2) fl=fi($s1) else fl=$1
if (fl==-1) return
fcd.x[fl]=0
}
//*** listvecs([LIST]) put the vecs in the list for use with eg uncode()
obfunc listvecs () { local ii,i,b localobj ol
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (argtype(1)==1) {ol=$o1 b=2} else b=1
if (!isassigned(ol)) {
ol=new List()
if (argtype(1)==1) $o1=ol
}
ol.remove_all
if (numarg()>=b) {
for i=b,numarg() {
if (argtype(i)==2) ii=fi($si) else ii=$i
if (ii==-1) return
ol.append(cob.v[ii])
}
} else {
for ii=0,m-1 ol.append(cob.v[ii])
}
return ol
}
//*** hash([COLA],[COLB] etc.) put the vecs in the list for use with eg uncode()
proc hash () { local ii,i,fl localobj o
if (eqobj(cob,out) && verbose) {
printf("hash() ERR: can't create hash col in 'Selected'\n") return }
o=new List()
if (numarg()==0) { // do all columns
resize("hashall")
for ii=0,m-2 o.append(v[ii])
} else {
tstr="hash"
for i=1,numarg() {
if (argtype(i)==0) fl=$i else fl=fi($si)
if (fl==-1) return
sprint(tstr,"%s_%s",tstr,s[fl].s)
o.append(v[fl])
}
resize(tstr)
}
pad()
v[m-1].hash(o)
}
//*** mat=tomat([MAT]) put the cols in cols of matrix
// mat=tomat(MAT,1) or mat=tomat(1) puts the cols in rows of matrix
obfunc tomat () { local ii,transpose,fo,sz localobj mat
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
fo=transpose=0 sz=size(1)
if (numarg()>=1) {
if (argtype(1)==0) transpose=$1 else {mat=$o1 fo=1}
}
if (numarg()>=2) transpose=$2
if (!isassigned(mat)) {
if (transpose) mat=new Matrix(m,sz) else mat=new Matrix(sz,m)
if (fo) $o1=mat
} else {
if (transpose) mat.resize(m,sz) else mat.resize(sz,m)
}
if (transpose) {for ii=0,m-1 mat.setrow(ii,cob.v[ii])
} else for ii=0,m-1 mat.setcol(ii,cob.v[ii])
return mat
}
//*** frmat(MAT) gets cols from cols of matrix
// frmat(MAT,1) gets the cols from rows of matrix
proc frmat () { local ii,transpose,rows,cols localobj mat
if (eqobj(cob,out)) {printf("frmat() ERR cannot reset 'Selected' to matrix\n") return}
fo=transpose=0
mat=$o1
if (numarg()>=2) transpose=$2
rows=mat.nrow cols=mat.ncol
if (transpose) {
if (cols!=size(1)) pad(cols)
if (rows!=m) resize(rows)
for ii=0,m-1 mat.getrow(ii,cob.v[ii])
} else {
if (rows!=size(1)) pad(rows)
if (cols!=m) resize(cols)
for ii=0,m-1 mat.getcol(ii,cob.v[ii])
}
}
//*** newnqs=transpose() create a new nqs that is the transpose of this one
obfunc transpose () { localobj mat,m2,oq
mat=tomat()
oq=new NQS()
oq.frmat(mat,1)
return oq
}
//*** prtval() use %g or %s to print values
proc prtval () { local i,typ,flag,otmp localobj f1
if (argtype(1)==0) {typ=$1 flag=0 i=2} else {f1=$o1 flag=1 typ=$2 i=3}
// oform() returns a double for printing an object
if ((typ==1 || typ==VECTY) && isassigned(oval)) {
otmp=oform(oval)
if (otmp==NOP) { typ=1
} else if (otmp==OK) { return // print nothing since being printed as side effect
} else { typ=0 nval=otmp // print a single numeric value
}
}
if (typ==0) sstr=dblform else sstr=strform
if (numarg()==i) {
sprint(sstr,"%s%s",sstr,$si)
} else if (numarg()==i+1) {
sprint(sstr,"%s%s",$si,sstr) i+=1 sprint(sstr,"%s%s",sstr,$si)
}
if (flag) {
if (typ==0) { f1.printf(sstr,nval)
} else if (typ==1) { f1.printf(sstr,oval)
} else if (typ==2) { f1.printf(sstr,sval)
} else if (typ==10) { for ii=0,4 f1.printf("%d ",scr.x[ii])
} else if (typ==-1) { f1.printf(sstr,sval) } // special code for externally provided list
} else {
if (typ==0) { printf(sstr,nval)
} else if (typ==1) { printf(sstr,oval)
} else if (typ==2) { printf(sstr,sval)
} else if (typ==10) { for ii=0,4 printf("%d ",scr.x[ii])
} else if (typ==-1) { printf(sstr,sval) } // special code for externally provided list
}
}
//** get("name",[IND]]) if omit IND take ind from first ind.x[0]
obfunc get () { local ty,fl,ix,outf,be,en localobj lo
outf=0
if (argtype(1)==0) { fl=$1 sstr2=s[fl].s
} else if (argtype(1)==2) { fl=fi($s1) sstr2=$s1 }
if (fl==-1) { return lo }
if (eqobj(cob,out)) { outf=1
if (verbose) printf(" *Selected* ") }
if (numarg()==1) {
if (outf) ix=0 else ix=ind.x[0]
} else ix=$2
if (ix<0 || ix>=cob.v[fl].size) {
printf("%s::get ERR ix %d out of range for %s (%s)\n",this,ix,sstr2,cob) return lo }
ty=fcd.x[fl]
if (ty==0) {lo=new Union(cob.v[fl].x[ix]) if (numarg()==3) $&3=lo.x
} else if (ty==1) {lo=new Union(fcdo,cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o
} else if (ty==FUNTY) {lo=methget(fl,cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o
} else if (ty==VECTY) { be=cob.v[fl].x[ix]
if (ix+1<cob.v[fl].size) en=cob.v[fl].x[ix+1]-1 else en=cob.v[fl].size-1
lo=new Union(fcdv.c(be,en)) if (numarg()==3) $o3=lo.o
} else if (ty==2) {lo=new Union(fcds,cob.v[fl].x[ix]) if (numarg()==3) $s3=lo.s
} else if (ty==-1){lo=new Union(fcdl.object(fl),cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o}
return lo
}
//** mget(row,col)
obfunc mget () { local ty,fl,ix,outf localobj lo
outf=0
ix=$1 fl=$2
if (ix<0 || ix>=cob.v[fl].size) {printf("%s::get ERR no %d,%d\n",this,fl,ix) return lo}
ty=fcd.x[fl]
if (ty==0) {lo=new Union(cob.v[fl].x[ix]) if (numarg()==3) $&3=lo.x
} else if (ty==1) {lo=new Union(fcdo,cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o
} else if (ty==2) {lo=new Union(fcds,cob.v[fl].x[ix]) if (numarg()==3) $s3=lo.s
} else if (ty==FUNTY) {lo=methget(fl,cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o
} else if (ty==-1){lo=new Union(fcdl.object(fl),cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o}
return lo
}
//** mset(row,col)
proc mset () { local ty,fl,ix,outf localobj lo
outf=0
ix=$1 fl=$2
if (ix<0 || ix>=cob.v[fl].size) {printf("%s::get ERR no %d,%d\n",this,fl,ix) return}
ty=fcd.x[fl]
if (ty==0) cob.v[fl].x[ix]=$3 else \
if (ty==1) fcds.o(cob.v[fl].x[ix])=$o3 else \
if (ty==2) fcds.o(cob.v[fl].x[ix]).s=$s3 else \
if (ty==-1)fcdl.object(fl).o(cob.v[fl].x[ix])=$o3
}
//** fetch(COLA,VAL,COLB) does fast select where COLA is VAL and returns value in COLB
// fetch(COLA,VAL) return the row number
// fetch(COLA,VAL,COLB,XO) places COLB object in XO
// ambiguity -- if 1,3 args can fetch from full db or selected else must do select first
func fetch () { local fl1,fl2,max,i localobj st,v0
if (eqobj(cob,out)) if (verbose) printf(" *Selected* ")
if (numarg()==1) {
if (argtype(1)==2) fl1=fi($s1) else fl1=$1
return cob.v[fl1].x[0]
} else if (numarg()==2) { // return the index
if (argtype(1)==2) fl1=fi($s1) else fl1=$1
if ((i=cob.v[fl1].indwhere("==",$2))<0){
printf("fetch ERR %d not found in %s\n",$2,s[fl1].s) return -1 }
return i
} else if (numarg()==3 || argtype(4)==1) {
if (argtype(1)==2) fl1=fi($s1) else fl1=$1
if (argtype(3)==2) fl2=fi($s3) else if (argtype(3)==0) fl2=$3 else {v0=$o3 fl2=-1}
if ((i=cob.v[fl1].indwhere("==",$2))<0) {
printf("fetch ERR %d not found in %s\n",$2,s[fl1].s) return -1 }
if (fl2>=0) {
if (numarg()==4) $o4=fcdo.o(cob.v[fl2].x[i])
return cob.v[fl2].x[i]
} else { // return row as a vector
v0.resize(0) for (ii=0;ii<m;ii+=1) v0.append(cob.v[ii].x[i])
return cob.v[0].x[i]
}
} else {
st=new String("select(-1,")
for i=1,numarg()-1 {
if (argtype(i)==0) sprint(st.s,"%s%g,",st.s,$i) else sprint(st.s,"%s\"%s\",",st.s,$si)
}
chop(st.s) sprint(st.s,"%s)",st.s)
execute(st.s,this)
i=numarg()
if (argtype(i)==0) fl2=$i else fl2=fi($si)
if (ind.size!=1 && verbose) printf("NQS fetch WARNING -- %d lines found\n",ind.size)
if (ind.size>0) return v[fl2].x[ind.x[0]] else return ERR
}
}
//** stat("COL","operation")
// stat("COL",VEC) // save into a vector: max,min,mean,sdev
// stat(NQS) // save all of them into another NQS
proc stat () { local i,vn
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (numarg()==0) {
for i=0,m-1 {
if (noheader) printf("%d:\t",i) else printf("%s:\t",s[i].s)
stat(i) // recursive call
}
return
}
if (argtype(1)==1) {
$o1.resize(5)
$o1.sethdrs("NAME","MAX","MIN","MEAN","SDEV")
$o1.strdec("NAME")
$o1.clear
for i=0,m-1 {
stat(i,scr[1]) // recursive call
$o1.append(scr[1],1)
$o1.set(0,i,s[i].s)
}
return
}
if (argtype(1)==0) vn=$1 else vn=fi($s1)
i=2
if (cob.size(1)<2) { printf("NQS:stat small NQS: %d\n",cob.size(1)) ok=0 } else ok=1
if (vn==-2) {
sprint(sstr2,"%s",cob.scr)
} else if (vn<0||vn>=m) {
return
} else if (fcd.x[vn]==CODTY) {
scr[1].resize(cob.v.size)
field=$i i+=1
cob.v[vn].uncode(scr[1],field)
sprint(sstr2,"%s",scr[1])
} else if (fcd.x[vn]==1) { // looking at a list of vectors
//if (oform()==NOP){printf("%s:stat ERR: set oform() to do stats on vectors or nqs\n",this)return}
scr[1].resize(0)
for ii=0,cob.v[vn].size-1 scr[1].append(oform(fcdo.o(cob.v[vn].x[ii])))
sprint(sstr2,"%s",scr[1])
} else {
sprint(sstr2,"%s",cob.v[vn])
}
if (numarg()<i) {
sprint(sstr, "printf(\"max=%%g; \",%s.max) ",sstr2)
sprint(sstr,"%s printf(\"min=%%g; \",%s.min) ",sstr,sstr2)
if (ok) sprint(sstr,"%s printf(\"mean=%%g; \",%s.mean) ",sstr,sstr2)
if (ok) sprint(sstr,"%s printf(\"stdev=%%g; \",%s.stdev) ",sstr,sstr2)
execute(sstr)
print ""
} else if (argtype(i)==1) { // a vector
$oi.resize(0)
if (ok) {$oi.append(cob.v[vn].max,cob.v[vn].min,cob.v[vn].mean,cob.v[vn].stdev)
} else {$oi.append(cob.v[vn].max,cob.v[vn].min,cob.v[vn].min,0) }
} else if (!ok) { return
} else for (;i<=numarg();i+=1) {
if (strm($si,"[(][)]$")) {
sfunc.left($si,sfunc.len($si)-2)
sprint(sstr,"printf(\"%s()=%%g; \",%s(%s))",$si,$si,sstr2)
} else sprint(sstr,"printf(\"%s=%%g; \",%s.%s)",$si,sstr2,$si)
execute(sstr)
print ""
}
}
//** iterator it() iterates over columns
// set's global tstr and XO to string bzw vec
iterator it () { local ii,nostr localobj st
nostr=i2=0
st=new String()
if (argtype(1)==2) st.s=$s1 else nostr=1 // regexp
for ii=0,m-1 {
if (nostr || strm(s[ii].s,st.s)) {
XO=cob.v[ii] execstr=s[ii].s i1=ii
iterator_statement
i2+=1
}
}
}
//** iterator ot() creates names for each col (same as col header) and goes through them all
iterator ot () { local i,na,val
if (! isobj(otl,"List")) { // create list to execute
otl=new List()
for i=0,m-1 {
Xo=new String(s[i].s)
if (fcd.x[i]==2) {
varstr(Xo.s,1)
sprint(Xo.s,"%s=%s.fcds.object(%s.cob.v[%d].x[i2]).s",Xo.s,this,this,i)
} else {
varstr(Xo.s)
sprint(Xo.s,"%s=%s.cob.v[%d].x[i2]",Xo.s,this,i)
}
otl.append(Xo)
}
Xo=nil
}
for (i2=0;i2<cob.v[0].size;i2+=1) {
for i=0,m-1 execute(otl.object(i).s)
iterator_statement
}
}
//** iterator qt(&x1,NAME1,&x2,NAME2,...)
// qt(&x1,NAME1,&x2,NAME2,...,&x)
// qt(&x1,NAME1,&x2,NAME2,...,5,7,&x) // just from 5 to 7
// qt(&x1,NAME1,&x2,NAME2,...,8) // ending at 8
// note &x arg location is opposite to that for ltr
// eg for sp.qt(&x,"PRID",&y,"POID",&z,"NC1",&ii,"WID1",&jj,"WT1") print x,y,z,ii,jj
// NB set qtset if resetting values
iterator qt () { local a,i,j,ii,na,val,noset,min,max,cntr localobj cols,cd
na=numarg()
cols=new Vector() cd=new Vector()
min=0 max=size(1)-1
if (argtype(na)==3) {i=cntr=na $&i=0 na-=1} else cntr=-1
if (argtype(na-1)==0) { // 2 values for min and max
i=na-1 min=$i i=na max=$i na-=2
}
if (na/2!=int(na/2)) { // odd number
if (argtype(na)==0) { i=na max=$i na-=1
} else {printf("%s::qt() needs even # of args\n",this) return }
}
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
//*** pick up column numbers
for (i=2;i<=na;i+=2) {
if (argtype(i)!=2) val=$i else val=fi($si)
cols.append(val) // cols has col #s
if (val<0 || val>=m) { if (argtype(i)==2) printf("(%s)",$si)
printf("%s::qt() ERR %d not found\n",this,val) return }
}
cd.copy(fcd) // cd gives codes for col's
//*** pick up the arguments
for (i=1;i<=na;i+=2) {
// can't do iteration over externally defined strings (eg -1) see useslist()
if (cols.x[int(i/2)]<0) continue
if (cd.x[cols.x[int(i/2)]]!=0) {
if (argtype(i)==3) {
printf("NQS::qt() WARNING using list index statt str for col %s\n",s[cols.x[int(i/2)]].s)
cd.set(cols.x[int(i/2)],0)
}
}
if (cd.x[cols.x[int(i/2)]]==2 && argtype(i)!=2) {
printf("%s::qt() ERR %s is strdec but arg %d not string\n",this,s[cols.x[int(i/2)]].s,i) return }
if (cd.x[cols.x[int(i/2)]]==1 && argtype(i)!=1) {
printf("%s::qt() ERR %s is odec but arg %d not obj\n",this,s[cols.x[int(i/2)]].s,i) return }
}
//*** iterate through setting local variables to values in NQS
for (ii=min;ii<=max;ii+=1) {
for (i=1;i<=na;i+=2) { j=cols.x[int(i/2)]
if (cd.x[j]==0) {
$&i=cob.v[j].x[ii]
} else if (cd.x[j]==2) {
$si=fcds.object(cob.v[j].x[ii]).s
} else if (cd.x[j]==1) {
$oi=fcdo.object(cob.v[j].x[ii])
} else {
printf("%s qt ERRA: %d %d\n",this,i,j)
continue
}
}
// for i=0,m-1 qtv.x[i]=v[i].x[ii] // if want these values need a separate vector
iterator_statement
//*** if qtset -> iterate through resetting NQS according to changed variables
if (qtset) for (i=1;i<=na;i+=2) { j=cols.x[int(i/2)]
if (cd.x[j]==0) {
cob.v[j].x[ii]=$&i
} else if (cd.x[j]==2) {
fcds.object(cob.v[j].x[ii]).s=$si
} else if (cd.x[j]==1) {
if (!eqojt(fcdo.object(cob.v[j].x[ii]),$oi)) {
printf("%s qt ERRB: can't reassign obj: %d %s %s\n",this,\
i,fcdo.object(cob.v[j].x[ii]),$oi)
}
}
}
if (cntr>-1) {i=cntr $&i+=1}
}
qtset=0 // turn back off
}
//** iterator ut(&x1,NAME1,&x2,NAME2,...)
// like qt but iterates over selected items without a copy (ie with selcp=0)
// ut(&x1,NAME1,&x2,NAME2,...,&x)
// ut(&x1,NAME1,&x2,NAME2,...,5,7,&x) // just from 5 to 7
// ut(&x1,NAME1,&x2,NAME2,...,8) // ending at 8
// note &x arg location is opposite to that for ltr
// eg for sp.ut(&x,"PRID",&y,"POID",&z,"NC1",&ii,"WID1",&jj,"WT1") print x,y,z,ii,jj
// NB set qtset if resetting values
iterator ut () { local a,i,j,ii,jj,na,val,noset,min,max,cntr localobj cols,cd
na=numarg()
a=allocvecs(cols,cd)
min=0 max=ind.size-1
if (argtype(na)==3) {i=cntr=na $&i=0 na-=1} else cntr=-1
if (argtype(na-1)==0) { // 2 values for min and max
i=na-1 min=$i i=na max=$i na-=2
}
if (na/2!=int(na/2)) { // odd number
if (argtype(na)==0) { i=na max=$i na-=1
} else {printf("%s::ut() needs even # of args\n",this) return }
}
if (eqobj(cob,out)) {printf("NQS WARNING: ut() called after full select(); switching\n")
cob=this }
//*** pick up column numbers
for (i=2;i<=na;i+=2) {
if (argtype(i)!=2) val=$i else val=fi($si)
cols.append(val) // cols has col #s
if (val<0 || val>=m) { if (argtype(i)==2) printf("(%s)",$si)
printf("%s::ut() ERR %d not found\n",this,val) return }
}
cd.copy(fcd) // cd gives codes for col's
//*** pick up the arguments
for (i=1;i<=na;i+=2) {
// can't do iteration over externally defined strings (eg -1) see useslist()
if (cols.x[int(i/2)]<0) continue
if (cd.x[cols.x[int(i/2)]]!=0) {
if (argtype(i)==3) {
printf("NQS::ut() WARNING using list index statt str for col %s\n",s[cols.x[int(i/2)]].s)
cd.set(cols.x[int(i/2)],0)
}
}
if (cd.x[cols.x[int(i/2)]]==2 && argtype(i)!=2) {
printf("%s::ut() ERR %s is strdec but arg %d not string\n",this,s[cols.x[int(i/2)]].s,i) return }
if (cd.x[cols.x[int(i/2)]]==1 && argtype(i)!=1) {
printf("%s::ut() ERR %s is odec but arg %d not obj\n",this,s[cols.x[int(i/2)]].s,i) return }
}
//*** iterate through setting local variables to values in NQS
for (jj=min;jj<=max;jj+=1) { ii=ind.x[jj]
for (i=1;i<=na;i+=2) { j=cols.x[int(i/2)]
if (cd.x[j]==0) {
$&i=cob.v[j].x[ii]
} else if (cd.x[j]==2) {
$si=fcds.object(cob.v[j].x[ii]).s
} else if (cd.x[j]==1) {
$oi=fcdo.object(cob.v[j].x[ii])
} else {
printf("%s ut ERRA: %d %d\n",this,i,j)
continue
}
}
iterator_statement
//*** if qtset -> iterate through resetting NQS according to changed variables
if (qtset) for (i=1;i<=na;i+=2) { j=cols.x[int(i/2)]
if (cd.x[j]==0) {
cob.v[j].x[ii]=$&i
} else if (cd.x[j]==2) {
fcds.object(cob.v[j].x[ii]).s=$si
} else if (cd.x[j]==1) {
if (!eqojt(fcdo.object(cob.v[j].x[ii]),$oi)) {
printf("%s ut ERRB: can't reassign obj: %d %s %s\n",this,\
i,fcdo.object(cob.v[j].x[ii]),$oi)
}
}
}
if (cntr>-1) {i=cntr $&i+=1}
}
dealloc(a)
qtset=0 // turn back off
}
//** iterator vt("proc",&x1,NAME1,&x2,NAME2,...)
proc vt () { local a,i,j,ii,na,val,noset,min,max,cntr localobj cols,cd,at
na=numarg()
a=allocvecs(cols,cd)
min=0 max=size(1)-1
if (argtype(na)==3) {i=cntr=na $&i=0 na-=1} else cntr=-1
if (argtype(na-1)==0) { // 2 values for min and max
i=na-1 min=$i i=na max=$i na-=2
}
if (na/2==int(na/2)) { // odd number
if (argtype(na)==0) { i=na max=$i na-=1
} else {printf("%s::vt() needs odd # of args\n",this) return }
}
if (eqobj(cob,out)) { printf(" vt() err: run .vt() on full set") return }
//*** pick up column numbers
for i=2,na {
if (argtype(i)!=2) val=$i else val=fi($si)
cols.append(val) // cols has col #s
if (val<0 || val>=m) { if (argtype(i)==2) printf("(%s)",$si)
printf("%s::vt() ERR %d not found\n",this,val) return }
if (fcd.x[val]!=0 && fcd.x[val]!=1) {
printf("%s::vt() ERR %d not handled (%d)\n",this,fcd.x[va],val) return }
}
//*** iterate through setting local variables to values in NQS
sprint(tstr,"%s.nqsvt(\"%s\",%s,%s,%s,%s)",cols,$s1,fcdo,fcd,vl,ind)
execute(tstr)
dealloc(a)
}
//** calc() spread-sheet functionality using vector functions
// takes a compound expression utilizing column names in slant brackets <>
// anything quoted can use either ' or \"
// eg sp.calc("<DIST>.c.mul(DELD).add(DEL)")
proc calc () { local ii,vn,exec
if (numarg()==0) {
printf("eg calc(\"<SCR>.copy(<COL1>.c.mul(<COL2>).add(5))\") \ntakes a compound expression utilizing column names in slant brackets <>\nanything quoted can use either ' slash quote.\n")
return
} else sstr=$s1
exec=1
if (argtype(2)==2) if (strcmp($s2,"NOEXEC")==0) exec=0
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
while (sfunc.tail(sstr,"<",sstr2)!=-1) {
sfunc.head(sstr2,">",sstr2)
if (strcmp(sstr2,"SCR")==0) {
sprint(sstr3,"%s",cob.scr)
} else if (isnum(sstr2)) {
sscanf(sstr2,"%d",&vn)
sprint(sstr3,"%s",cob.v[vn])
} else if ((vn=fi(sstr2))==-1) {
return // error
} else {
sprint(sstr3,"%s",cob.v[vn])
}
sprint(sstr2,"<%s>",sstr2)
repl_mstr(sstr,sstr2,sstr3,sstr4)
}
repl_mstr(sstr,"'","\"",sstr4)
if (exec) execute(sstr)
}
//** sort () sort according to one index
func sort () { local beg,ii,vn
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (argtype(1)==0) vn=$1 else vn=fi($s1)
if (vn<0||vn>=m) return -1
if (fcd.x[vn]==1) {
cob.scr.resize(0)
for ii=0,cob.v[vn].size-1 cob.scr.append(oform(fcdo.o(cob.v[vn].x[ii])))
if (cob.scr.x[0]==NOP) { // looking at a list of vectors
printf("NQS:sort ERR define oform to sort obj field %s\n",s[vn].s) return 0 }
cob.scr.sortindex(cob.ind)
} else {
if (cob.v[vn].ismono() && numarg()==1) {
printf("NQS sort %s already ordered\n",cob.v[vn]) return vn }
cob.v[vn].sortindex(cob.ind)
}
if (numarg()==2) if ($2==-1) cob.ind.reverse
fewind()
return vn
}
//** vsort(vec) sort according to vec which may have redundancy
func vsort () { local beg,ii,x localobj o
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
o=$o1
if (numarg()==2) if ($2==-1) o.reverse
cob.scr.resize(cob.v.size)
for (beg=0;beg<m;beg+=50) { // fewind() can only handle vecst.mod:VRRY vecs at a time
tmplist.remove_all
for (ii=beg;ii<beg+50 && ii<m;ii+=1) tmplist.append(cob.v[ii])
x=cob.scr.fewind(o,tmplist,1)
}
return x
}
//** percl ("FIELD",n %ile) check whether the first n% of the vector are in the top n %ile
// usage -- reverse sort according to 1 field and then ask if other field is in top n %ile
func percl () { local beg,ii,vn,nile,sz
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (argtype(1)==0) vn=$1 else vn=fi($s1)
if (vn<0||vn>=m) return -1
sz=cob.v[vn].size
nile=int($2*sz/100)
scr[1].copy(cob.v[vn]) scr[1].sort() scr.resize(0) scr.copy(scr[1],sz-nile-1,sz-1)
scr.reverse() // the top n-ile percentile
scr[2].resize(0) scr[2].copy(cob.v[vn],0,nile) // the first set of values from NQS
// scr[1].insct(scr,scr[2]) // find all common values
for ii=0,scr[2].size-1 if (scr.contains(scr[2].x[ii])) return ii // which one is top of scr[2]
return -1
}
// family("COLA",val,"COLB","COLC")
// pick out rows that have are same as row with "COLA" val except that COLB COLC
// etc. can be anything
func family () { local a,i,ii,vn,va,nile,sz,om localobj key,arg
tog("DB") // start at full db
a=allocvecs(key,arg)
sz=size(1)
tmplist.remove_all arg.resize(0) key.resize(0)
if (select(-1,$s1,$2)!=1) printf("WARNING: NQS family found more than 1 %s=%g\n",$s1,$2)
va=fi($s1)
scr.resize(0) scr.append(va)
for i=3,numarg() scr.append(fi($si))
for i=0,m-1 if (! scr.contains(i)) {
tmplist.append(v[i])
key.append(EQU)
arg.append(v[i].x[ind.x[0]],0)
}
ind.resize(v.size)
ind.slct(key,arg,tmplist) // run select function
if (ind.size>0) {
out.ind.copy(ind)
aind()
cob=out
} else if (verbose) printf("None selected\n")
dealloc(a)
return ind.size
}
// psel(%ile,"COLA","COLB","COLC")
// psel("COLA",%ileA,"COLB",%ileB,"COLC",%ileC)
// neg %ile means bottom -- eg 10 is largest 10% and -10 is smallest 10%
// return top percentile in these columns
func psel () { local a,i,ii,vn,nile,sz,om localobj key,arg
tog("DB") // start at full db
a=allocvecs(key,arg)
om=numarg()-1
sz=size(1)
tmplist.remove_all arg.resize(0) key.resize(0)
if (argtype(1)==0) {
if (int($1*sz/100)==0) { printf("%s pselERR: unable %d%% of %d\n",this,$1,sz)
return -1 }
key.resize(om)
if ($1>0) {
nile=sz-int($1*sz/100)
key.fill(GTE)
} else {
nile=-int($1*sz/100)
key.fill(LTE)
}
for i=2,numarg() {
if (argtype(i)==0) vn=$i else vn=fi($si)
if (vn<0||vn>=m) return -1
tmplist.append(v[vn])
scr[1].copy(v[vn])
scr[1].sort()
arg.append(scr[1].x[nile],0) // 2nd arg for GTE ignored
if (verbose) printf("%s:%g ",$si,scr[1].x[nile])
}
} else for i=1,numarg() {
tstr=$si
vn=fi($si) i+=1
if (int($i*sz/100)==0) { printf("NQS psel(): WARNING: ignoring %d%% of %d\n",$i,sz)
continue }
if (vn<0||vn>=m) return -1
tmplist.append(v[vn])
scr[1].copy(v[vn])
scr[1].sort()
if ($i>0) {
nile=sz-int($i*sz/100)
key.append(GTE)
} else {
nile=-int($i*sz/100)
key.append(LTE)
}
arg.append(scr[1].x[nile],0) // 2nd arg for GTE ignored
if (verbose) printf("%s:%g ",tstr,scr[1].x[nile])
}
ind.resize(v.size)
ind.slct(key,arg,tmplist) // run select function
if (ind.size>0) {
out.ind.copy(ind)
aind()
cob=out
} else if (verbose) printf("None selected\n")
if (verbose) print ""
dealloc(a)
return ind.size
}
//** uniq(COLNAME) will pick out unique row (1st) for the chosen column
func uniq () { local vn
if (! eqobj(cob,out)) {printf("Only run NQS:uniq() on prior selected set.\n") return -1}
vn=sort($s1)
cob.ind.resize(cob.v.size)
cob.ind.redundout(cob.v[vn],1)
fewind()
return cob.ind.size
}
//** elimrepeats(COLA[,COLB,...])
func elimrepeats () { local a,b,i,ii,indflag localobj sl,tl,v1
if (eqobj(cob,out)) {printf("%s ERR: run elimrepeats on full db\n",this) return 0.}
if (size(1)==0) { printf("%s:elimirepeats Empty NQS\n",this) return 0.}
a=allocvecs(v1) b=1 indflag=0
sl=new List() tl=new List()
if (numarg()==0) {
for ii=0,m-1 { sl.append(v[ii]) v1.append(ii) }
b=numarg()+1
} else if (argtype(1)==0) if ($1==-1) {b=2 indflag=1}
for i=b,numarg() {
if (argtype(i)==0) ii=$i else if ((ii=fi($si))==-1) return 0
sl.append(v[ii])
v1.append(ii)
}
for ii=0,m-1 if (!v1.contains(ii)) tl.append(v[ii])
for (ii=v1.size-1;ii>=0;ii-=1) sort(v1.x[ii]) // sort them in the reverse order of calling
ii=ind.mredundout(sl,indflag,tl)
dealloc(a)
return ii
}
//** covarc("vCol") -- generate covariance matrix from vectors in a single column
obfunc covarc () { local a,fl,n,m localobj mat,xo,v1
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if ((fl=fi($s1))==-1) return -1
if (fcd.x[fl]!=1) {printf("Must be an obj column\n") return -1}
xo=get(fl,0).o
if (!isojt(xo,ind)) {printf("Must be an vec column\n") return -1}
n=size(1) // number of data vectors
m=xo.size // size of vector
a=allocvecs(v1)
mat=new Matrix(m,m)
cob.v[fl].covar(fcdo,v1)
mat.from_vector(v1)
dealloc(a)
return mat
}
//** tomatc("vCol") -- return matrix of vectors from a single column; load into rows of mat
obfunc tomatc () { local a,fl,n,m,ii localobj mat,xo,v1
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if ((fl=fi($s1))==-1) return -1
if (fcd.x[fl]!=1) {printf("Must be an obj column\n") return -1}
xo=get(fl,0).o
if (!isojt(xo,ind)) {printf("Must be an vec column\n") return -1}
n=size(1) // number of data vectors
m=xo.size // size of vector
mat=new Matrix(n,m)
for qt(xo,fl,&ii) mat.setrow(ii,xo)
return mat
}
//** shuffle()
proc shuffle () { local a,b,i,ii,indflag localobj sl,tl,v1
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (size(1)==0) { printf("%s:shuffle Empty NQS\n",this) return}
if (eqobj(cob,out)) out.ind.copy(ind)
rdmord(cob.ind,cob.v.size)
fewind()
}
//** fewind () -- index all of the vecs in place using vecst.mod::fewind()
proc fewind () {
cob.scr.resize(cob.v.size)
for (beg=0;beg<m;beg+=50) { // fewind() can only handle vecst.mod:VRRY vecs at a time
tmplist.remove_all
for (ii=beg;ii<beg+50 && ii<m;ii+=1) tmplist.append(cob.v[ii])
cob.scr.fewind(cob.ind,tmplist)
}
cob.ind.resize(0) // prevents reusing it
}
//** aind () -- index all of the vecs into out list
proc aind () { local beg,ii
for (beg=0;beg<m;beg+=10) {
tmplist.remove_all vlist.remove_all
for ii=beg,beg+10 if (ii<m) {
out.v[ii].resize(ind.size)
tmplist.append(v[ii])
vlist.append(out.v[ii])
}
ind.findx(tmplist,vlist)
}
}
//** append(VEC[,begin]) appends to ends of given vectors
// append(x1,x2,...); append(NQS)
proc append () { local ii,jj,i,flag,begin,o1fcd localobj xo
cob=this
if (m==0) { printf("%s append ERR0, attempted append to uninitialized NQS\n",this) return }
if (argtype(1)==1 && fcd.x[0]!=1) {
if (isobj($o1,"Vector")) { // a vector of values
if (numarg()>1) begin=$2 else begin=0
if (begin+$o1.size>m) {
printf("%s append ERR1: vec %s too large; doing nothing: %d>%d",this,$o1,begin+$o1.size,m)
} else {
for i=begin,begin+$o1.size-1 v[i].append($o1.x[i-begin])
}
} else if (isobj($o1,"NQS")) { // another NQS to add onto end
if ($o1.m != m) {
printf("%s append ERR1a, %s size %d!= %s size %d?\n",this,this,m,$o1,$o1.m)
return }
for ii=0,m-1 {
o1fcd=$o1.fcd.x[ii]
if (o1fcd==0) { v[ii].append($o1.cob.v[ii])
} else for jj=0,$o1.size(1)-1 {
xo=$o1.get(ii,jj)
if (o1fcd==1) oval=xo.o else sval=xo.s
v[ii].append(newval(o1fcd,ii))
}
}
} else if (isobj($o1,"List")) { // list of vectors to add on
if ($o1.count() != m) {
printf("%s append ERR1b, %s size %d!= %s size %d?\n",this,this,m,$o1,$o1.count())
return }
for ii=0,m-1 v[ii].append($o1.o(ii))
} else { printf("%s append ERR1c, what is %s?\n",this,$o1) }
return
}
if (argtype(1)==2) if ((ii=fi($s1,"NOERR"))!=-1) { // a field name
for i=1,numarg() {
if ((ii=fi($si))==-1) return
i+=1
if (argtype(i)==0) {
v[ii].append($i)
} else {
if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
v[ii].append(newval(argtype(i),ii))
}
}
return
}
if (numarg()>m) { printf("%s append ERR2: args>m; doing nothing\n",this) return }
if (numarg()<=m) {
if (numarg()<m) printf("NQS::append() WARNING only filling %d/%d cols for %s\n\tuse NQS.pad",numarg(),m,this)
for ii=0,numarg()-1 {
i=ii+1
if (argtype(i)==0) {
v[ii].append($i)
} else {
if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
v[ii].append(newval(argtype(i),ii))
}
}
return
}
}
//** appi(index,VEC) or append(index,x1,x2,...) appends to ends of vectors starting at index
proc appi () { local i,ix,n
cob=this
if (argtype(1)==2) ix=fi($s1) else ix=$1
if (numarg()==2 && argtype(2)==1 && fcd.x[ix]==0) { // a vector
if ($o2.size>m-ix) {
printf("%s appi ERR1: vec too large; doing nothing %d %d %d %d\n",this,m,$o2.size,ix,m-ix)
} else {
n=-1
for i=ix,ix+$o2.size-1 v[i].append($o2.x[n+=1])
}
} else {
if (numarg()-1>m-ix) {
printf("%s appi ERR2: args>m; doing nothing",this)
return
}
for i=2,numarg() {
if (argtype(i)==0) {
v[ix+i-2].append($i)
} else {
if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
v[ix+i-2].append(newval(argtype(i),ix+i-2))
}
}
}
}
//** map(FUNC,arg1,...) map $s1 command to other args, replacing strings with vectors as found
// eg nqs.map("gg",0,"volt","cai",2)
proc map () { local i,agt,wf
if (numarg()==0) {
printf("map(FUNC,arg1,...) apply function to args using names for columns.\n")
return }
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
sprint(sstr,"%s(",$s1) // the command
wf=0
for i=2,numarg() { // the args
agt=argtype(i)
if (agt==0) {
sprint(sstr,"%s%g,",sstr,$i)
} else if (agt==1) {
sprint(sstr,"%s%s,",sstr,$oi)
} else if (agt==2) {
if ((vn=fi($si))==-1) {
sprint(sstr,"%s\"%s\",",sstr,$si)
printf("NQS.map WARNING: including raw string: %s\n",$si) wf=1
} else if (fcd.x[vn]==1) { // look at a list of obj's
cob.scr.resize(0)
for ii=0,cob.v[vn].size-1 cob.scr.append(oform(fcdo.o(cob.v[vn].x[ii])))
if (cob.scr.x[0]==NOP) {
printf("map WARNING: oform not set for %s interp; replacing with fcdo indices\n",$si)
cob.scr.copy(cob.v[vn])
}
sprint(sstr,"%s%s,",sstr,cob.scr)
} else if (vn==-2) { // code for scr vector
sprint(sstr,"%s%s,",sstr,cob.scr)
} else {
sprint(sstr,"%s%s,",sstr,cob.v[vn])
}
} else { printf("argtype %d for arg %d not implemented for NQS:map\n",agt,i) return }
}
chop(sstr) sprint(sstr,"%s)",sstr)
if (wf && !batch_flag) if (boolean_dialog(sstr,"CANCEL","EXECUTE")) return
// print sstr
execute(sstr)
}
//*** gr() use map to graph
// need to assign .crosshair_action so can do visual select procedure
proc gr () { local i,nm,gn,col,lne,f3d,y,x,done localobj symb,st
nm=numarg() gn=0 f3d=-1 st=new String2()
col=2 lne=4 stone=0
done=0
if (sfunc.len(marksym)==0) marksym="o"
sprint(tstr,"symb=\"%s\"",marksym) execute(tstr) // set global symb
if (argtype(1)==2) st.s=$s1 else if (argtype(1)==0) st.s=s[$1].s
if (argtype(2)==2) st.t=$s2 else if (argtype(2)==0) if ($2>=0) st.t=s[$2].s else {
stone=1 } // use -1 as place
if (nm==0) {
print "gr(\"Y\",\"X\"[,\"Z\",g#,col,line]); Y or X can be col# or col#,-1; 'Z' must be str"
return
} else if (nm==1) { map("gg",0,st.s,1,col,lne) stone=done=1
} else if (nm==2) { map("gg",0,st.s,st.t,col,lne) done=1 }
i=3
if (! done) {
if (argtype(i)==2) {f3d=fi($si) i+=1}
if (argtype(i)==0) {gn=$i} else if (argtype(i)==1) {gn=ojtnum($oi) g[gn]=$oi}
i+=1 if (i<=nm) col=$i
i+=1 if (i<=nm) lne=$i
if (f3d!=-1) {
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (!gvmarkflag) {printf("%s gr ERR: 3D and gvmarkflag=0\n",this) return}
y=fi(st.s) x=fi(st.t)
if (lne==1) lne=2 else lne-=2 // will augment below
if (x==-1 || y==-1) {printf("%s gr ERR: %s,%s not fi()\n",this,st.s,st.t) return}
for i=0,cob.v.size-1 {
if (i%9==0) lne+=2
g[gn].mark(cob.v[x].x[i],cob.v[y].x[i],marksym,lne,cob.v[f3d].x[i]%9+1,4)
}
} else if (stone) {
map("gg",gn,st.s,1,col,lne)
} else { // print gn,col,lne
map("gg",gn,st.s,st.t,col,lne)
}
}
g[gn].color(col)
// g[gn].label(0.05,0.95,st.s)
// if (nm>=2) g[gn].label(0.85,0.05,st.t)
g[gn].color(1)
if (!stone) {
setgrsel(g[gn],fi(st.s),fi(st.t))
setchsel(g[gn],fi(st.s),fi(st.t))
}
}
//** grsel(): CTL-hit == Crosshair
// SHT-hit == resize
// hit-drag-release == show in square
// SHT-hit-drag-release == show new thing there
// Type: press (2), drag (1), release (3)
// Keystate: META-SHT-CTL eg 101=5 is META-CTL
proc setgrsel () {
$o1.menu_remove("Selector")
sprint(tstr,"proc p(){grsel($1,$2,$3,$4,%d,%d)}",$2,$3)
execute1(tstr,this)
$o1.menu_tool("Selector", "p")
}
proc setchsel () {
sprint(tstr,"proc q(){chsel($1,$2,$3,%d,%d)}",$2,$3)
execute1(tstr,this)
$o1.crosshair_action("q")
}
grsbegx=grsbegy=1e9
proc grsel () { local type, x0, y0, keystate, fl1,fl2,sel
type=$1 x0=$2 y0=$3 keystate=$4 fl1=$5 fl2=$6
if (type==3) {
if (grsbegx==1e9) { // no drag was done
if ((sel=select(fl2,"~",x0,fl1,"~",y0))!=0) {
pr()
} else print "Can't find ",s[fl2].s,"~ ",x0,s[fl1].s,"~ ",y0
} else { // consider a rectangle
order(&grsbegx,&x0) order(&grsbegy,&y0)
if ((sel=select(fl2,"[]",grsbegx,x0,fl1,"[]",grsbegy,y0))!=0) {
if (keystate==0) { grsel2()
} else if (keystate==3) { // CTL or SHIFT alone are being used by fvwm2
pr() // print grsbegx,x0,grsbegy,y0
}
} else printf("Can't find %s %g-%g; %s %g-%g\n",s[fl2].s,grsbegx,x0,s[fl1].s,grsbegy,y0)
grsbegx=grsbegy=1e9
}
} else if (type==1 && grsbegx==1e9) {grsbegx=x0 grsbegy=y0 }
}
// order(&x,&y) returns the values in order
proc order () { local tmp
if ($&2<$&1) { tmp=$&2 $&2=$&1 $&1=tmp }
}
proc chsel () { local ascii, x0, y0, fl1,fl2,sel
x0=$1 y0=$2 ascii=$3 fl1=$4 fl2=$5
if ((sel=select(fl2,"~",x0,fl1,"~",y0))!=0) {
if (ascii==32) { chsel2()
} else pr()
} else print "Can't find ",s[fl2].s,"~ ",x0,s[fl1].s,"~ ",y0
}
//** apply function or .op to every selected vector -- ignore return val, see applf
proc apply () { local i,fl
if (numarg()==0) {
printf("apply(FUNC,COL1,...) apply function or .op to every selected vector.\n")
printf("must be function, not proc, since will return value.\n")
return }
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (numarg()==1) for i=0,m-1 { // apply to all vectors
if (strm($s1,"^\\.")) sprint(sstr,"%s%s" ,cob.v[i],$s1) else {
sprint(sstr,"%s(%s)",$s1,cob.v[i]) }
execute(sstr)
} else for i=2,numarg() {
if (argtype(i)==0) fl=$i else if ((fl=fi($si))==-1) return
if (fl==-2) sprint(sstr2,"%s",cob.scr) else sprint(sstr2,"%s",cob.v[fl])
if (strm($s1,"^\\.")) sprint(sstr,"%s%s" ,sstr2,$s1) else {
sprint(sstr,"%s(%s)",$s1,sstr2) }
execute(sstr)
}
}
//** applf(FUNC,COL) function or .op which returns a value
func applf () { local min,max,a,i,fl,ret,na,flag localobj v1,v2
na=numarg()
if (na==0) {
printf("applf(FUNC,'COLA'[,...,vec]) apply function or .op to selected cols.\n")
printf("applf(FUNC,vec) apply function or .op to all cols.\n")
printf("with more than one column need a final vector to copy results to\n")
printf("must use function, not proc, since will keep return value.\n")
return -1 }
a=allocvecs(v1,v2)
v1.resize(1)
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (argtype(na)==1) {flag=na na-=1} else flag=0 // flag to copy onto an output vector
if (na==1) { min=0 max=m-1 } else { min=2 max=na }
for i=min,max {
if (na==1) { fl=i
} else {if (argtype(i)==0) fl=$i else if ((fl=fi($si))==-1) return -1}
if (fl==-2) sprint(sstr2,"%s",cob.scr) else sprint(sstr2,"%s",cob.v[fl])
if (strm($s1,"^\\.")) sprint(sstr,"%s.x[0]=%s%s" ,v1,sstr2,$s1) else {
sprint(sstr,"%s.x[0]=%s(%s)",v1,$s1,sstr2) }
execute(sstr)
v2.append(v1.x[0])
}
if (flag) {i=flag $oi.copy(v2)}
ret=v2.x[0]
dealloc(a)
return ret
}
//** fill(NAME,val[,NAME1,val1 ...])
// fill each selected vector with next arg
func fill () { local i,fl,fl2,x
if (numarg()==0) {
printf("fill(NAME,val[,NAME1,val1 ...])\n\tfill each selected vector with val\nval can be num, vector, or other col name\n")
return -1}
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
for i=1,numarg() {
fl=fi($si) i+=1
if (fl==-1) return -1
field=0
if (fcd.x[fl]==CODTY) { // code field
field=$i i+=1
}
if (argtype(i)==0) {
if (field>0) cob.v[fl].uncode(field,$i) else cob.v[fl].fill($i)
} else if (argtype(i)==1) {
if (!isobj($oi,"Vector")){
printf("%s:fill() ERRa: only fill with vector: %s\n",this,$oi) return -1}
if ($oi.size!=cob.v.size){
printf("%s:fill() ERRb: wrong vec size: %d!=%s:%d\n",this,cob.v.size,$oi,$oi.size) return -1}
if (field>0) cob.v[fl].uncode(field,$oi) else cob.v[fl].copy($oi)
} else if (argtype(i)==2) {
fl2=fi($si,"NOERR")
if (fl2== -1) { // add this string to this field?
if (fcd.x[fl]==2) {
sval=$si
x=newval(2,fl)
cob.v[fl].fill(x)
} else {
printf("%s:fill() ERRc: trying to fill field %s with string %s\n",this,s[fl].s,$si)
return -1
}
} else if (field>0) {
cob.v[fl].uncode(field,cob.v[fl2])
} else cob.v[fl].copy(cob.v[fl2])
i+=1
}
}
return cob.v[fl].size
}
//** fillin(NAME,val[,NAME1,val1 ...])
// fill in place according to indices in ind -- use with selcp==0
// can also do after a regular select() ie selcp==1 and avoid needing a delect
proc fillin () { local i,fl
if (numarg()==0) {
printf("fillin(NAME,val[,NAME1,val1 ...])\n\tfill selected vectors in place\n")
printf("\tuse after select(-1,...) eg selcp==0\n")
return
}
scr.resize(0)
for (i=2;i<=numarg();i+=2) scr.append($i)
tmplist.remove_all
for (i=1;i<=numarg();i+=2) {
if (argtype(i)==2) {
if ((fl=fi($si))==-1) return
} else fl=$i
tmplist.append(v[fl])
}
ind.sindv(tmplist,scr)
}
//** fillv(NAME,v1[,NAME1,v2 ...])
// fill from vectors v1,v2,..., places in ind -- use with selcp=0
proc fillv () { local i,fl
if (numarg()==0) {
printf("fillv(NAME,vec1[,NAME1,vec2 ...])\n\tfill selected vectors from vectors\n")
printf("\tuse after select() with selcp==0\n")
return
}
tmplist.remove_all vlist.remove_all
for (i=1;i<=numarg();i+=2) {
if (argtype(i)==2) {
if ((fl=fi($si))==-1) return
} else fl=$i
tmplist.append(v[fl])
}
for (i=2;i<=numarg();i+=2) vlist.append($oi)
ind.sindx(tmplist,vlist)
}
//** pr() print out vectors
// eg pr("COLA","COLB",3,7)
// last args are max or min-max rows
// first set of args can be any of: col_names, file object, file name (not same as col name),
// vector giving col numbers
func pr () { local ii,i,min,max,na,flag,jj,e,fout,sz,nohdr
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (m==0) {printf("%s EMPTY",this) return 0}
scr[1].resize(0)
nohdr=fout=flag=min=0 max=cob.v.size-1 na=numarg()
nohdr=noheader
if (argtype(na)==0 && argtype(na-1)==0) { // pick up the limits first
i=na na-=2
max=$i i-=1 min=$i
} else if (argtype(na)==0) {
i=na na-=1
if ($i>=0) max=$i else min=max+$i // allow printing the end
}
for i=1,na {
if (argtype(i)==1) {
if (isobj($oi,"Vector")) { flag=1 // column indices in a vector
scr[1].copy($oi)
} else if (isobj($oi,"File")) { fout=1
} else { printf("NQS::pr() Unknown object: %s\n",$oi) return 0 }
} else if (argtype(i)==2) {
if (fi($si,"NOERR")!=-1) { // column identifier to pick up
scr[1].append(fi($si)) flag=1
} else if (strcmp($si,"NOHEADER")==0) { nohdr=1
} else if (strm($si,"[<>]")) { flag=2 // something to calculate
} else { // assume it's a file name
if (fout) { fi($si) return 0 } // already picked up a filename
if (!tmpfile.wopen($si)) printf("%s:Can't open %s for printing\n",this,$si)
fout=1
printf("==== WARNING: printing ascii to file %s ====\n",$si)
}
}
}
if (flag==0) scr[1].indgen(0,m-1,1) // didn't pick up any columns
if (scr[1].min<0 || scr[1].max>m-1) { printf("NQS:pr() bad col values: ") vlk(scr[1]) return 0 }
if (max>size(1)){ max=size(1)-1
printf("NQS:pr WARNING: %d rows requested but %s size=%d\n",max,this,size(1)) }
if (min>size(1)){printf("NQS:pr ERROR: %s size=%d < min %d\n",this,size(1),min) return 0}
if (!fout && flag!=2) print ""
if (flag==2) {
calc($s1,"NOEXEC")
sprint(sstr,"XO=%s",sstr)
execute(sstr)
vlk(XO,min,max)
} else {
sz=scr[1].size-1
if (!nohdr) {
printf("%s",tabform)
for i=0,sz {
ii=scr[1].x[i]
if (ii==-1) return -1
if (fout) {
if (ii<0) tmpfile.printf("%s%s",is[-ii].s,tabform) else {
tmpfile.printf("%s(%d)%s",s[ii].s,ii,tabform) }
} else {
if (ii<0) printf("%s%s",is[-ii].s,tabform) else printf("%s(%d)%s",s[ii].s,ii,tabform)
}
}
if (fout) tmpfile.printf("\n") else printf("\n")
}
for jj=min,max {
printf("%s",tabform)
for i=0,sz { ii=scr[1].x[i]
if (ii==-2) { printf(dblform,cob.scr.x[jj])
} else if (ii==-3) {
if (fout) tmpfile.printf(dblform,cob.ind.x[jj]) else printf(dblform,cob.ind.x[jj])
} else {
if (fout) { prtval(tmpfile,(e=getval(ii,cob.v[ii].x[jj],jj)),tabform)
} else if (sz) { prtval( (e=getval(ii,cob.v[ii].x[jj],jj)),tabform)
} else { prtval( (e=getval(ii,cob.v[ii].x[jj],jj)),tabform) }
if (e==ERR) return ERR
}
}
if (fout) tmpfile.printf("\n") else if (sz) print "" else printf(" ")
}
}
if (fout) tmpfile.close
return 0
}
//** prs() print out vectors
// eg prs("COLA","COLB",3,7)
func prs () { local ii,i,min,max,na,flag,jj,kk,e,fout,sz,nohdr
if (eqobj(cob,out)) printf("NQS WARNING: prs() called after full select(); switching\n")
cob=this
if (m==0) {printf("%s EMPTY",this) return 0}
nohdr=flag=min=0 max=ind.size-1 na=numarg()
if (na>=2) {
if (argtype(na-1)==0) {
i=na na-=2
max=$i i-=1 min=$i
flag=1 // took care of numbers
}}
if (!flag && na>=1) {
if (argtype(na)==0) {
i=na na-=1
if ($i>=0) max=$i else min=max+$i // allow printing the end
}
}
// reuse flag -- means printing only certain cols
fout=flag=0 i=1 // fout==1 means print out to file
if (na>=1) if (argtype(1)==2) if (fi($s1,"NOERR")==-1) { // call it a file name
if (!tmpfile.wopen($s1)) printf("%s:Can't open %s for printing\n",this,$s1)
fout=1 i+=1
printf("==== WARNING: printing ascii to file %s ====\n",$s1)
if (numarg()==2) if (argtype(2)==2) if (strcmp($s2,"NOHEADER")==0) {nohdr=1 i+=1}
}
if (na>=i) if (argtype(i)==2 || argtype(i)==1) flag=1 // column names
if (max>ind.size()){ max=ind.size()-1
printf("NQS:prs WARNING: %d rows requested but %s size=%d\n",max,this,ind.size()) }
if (min>size(1)){printf("NQS:prs ERROR: %s size=%d < min %d\n",this,size(1),min) return 0}
if (!fout) print ""
if (flag) {
scr[1].resize(0)
if (argtype(i)==1) scr[1].copy($oi) else for (;i<=na;i+=1) scr[1].append(fi($si))
sz=scr[1].size-1
if (!nohdr) { for i=0,sz {
ii=scr[1].x[i]
if (ii==-1) return -1
if (fout) {
if (ii<0) tmpfile.printf("%s\t",is[-ii].s) else tmpfile.printf("%s(%d)\t",s[ii].s,ii)
} else {
if (ii<0) printf("%s\t",is[-ii].s) else printf("%s(%d)\t",s[ii].s,ii)
}
} if (fout) tmpfile.printf("\n") else printf("\n") }
for kk=min,max { jj=ind.x[kk]
for i=0,sz { ii=scr[1].x[i]
if (ii==-2) { printf(dblform,cob.scr.x[jj])
} else if (ii==-3) {
if (fout) tmpfile.printf(dblform,cob.ind.x[jj]) else printf(dblform,cob.ind.x[jj])
} else {
if (fout) { prtval(tmpfile,(e=getval(ii,cob.v[ii].x[jj],jj)),tabform)
} else if (sz) { prtval( (e=getval(ii,cob.v[ii].x[jj],jj)),tabform)
} else { prtval( (e=getval(ii,cob.v[ii].x[jj],jj)),tabform) }
if (e==ERR) return ERR
}
}
if (fout) tmpfile.printf("\n") else if (sz) print "" else printf(" ")
}
} else {
if (!nohdr) {
if (fout) for ii=0,m-1 tmpfile.printf("%4.4s(%d) ",s[ii].s,ii) else {
for ii=0,m-1 printf("%4.4s(%d) ",s[ii].s,ii) }
if (fout) tmpfile.printf("\n") else print ""
}
for kk=min,max { jj=ind.x[kk]
for ii=0,m-1 {
if (fout) prtval(tmpfile,e=getval(ii,cob.v[ii].x[jj],jj),tabform) else {
prtval( e=getval(ii,cob.v[ii].x[jj],jj),"")
printf("(%d)%s",ii,tabform)
}
if (e==ERR) return ERR
}
if (fout) tmpfile.printf("\n") else print ""
}
}
if (fout) tmpfile.close
return max-min+1
}
//** prn() print out single index from vectors
proc prn () { local jj,ii,ix,max,e
ix=$1
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (numarg()==2) max=$2 else max=ix
for jj=ix,max {
if (jj<0 || jj>=cob.v[0].size) {
printf("prn: Index out of range (%d)\n",cob.v[0].size) return }
for ii=0,m-1 {
printf("%s:",s[ii].s)
prtval(e=getval(ii,cob.v[ii].x[jj],jj)," ")
if (e==ERR) return
}
print ""
}
}
//** zvec() -- clear -- resize all the vectors to 0
proc clear () { if (numarg()==1) zvec($1) else zvec() }
proc zvec () { local ii,sz
cob=this
if (numarg()==1) sz=$1 else sz=0
// fcds.remove_all fcds.append(new String("`EMPTY'"))
if (isassigned(fcdo)) fcdo.remove_all
if (isassigned(fcdv)) fcdv.resize(0)
if (sz>0) vlsz(vl,sz,0)
vlsz(vl,0)
}
//** pad() -- bring all vectors up to same length (of v[0])
func pad () { local sz,ii localobj v1
sz=-1
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
info.set("pads",v1=new Vector(m))
for ii=0,m-1 v1.x[ii]=cob.v[ii].size
for ii=0,m-1 if (cob.v[ii].size>sz) sz=cob.v[ii].size
if (argtype(1)==0) sz=$1 else for ii=0,m-1 if (cob.v[ii].size>sz) sz=cob.v[ii].size
if (argtype(2)==0) vlsz(cob.vl,sz,$2) else vlsz(cob.vl,sz) // optional fill value
return sz
}
obfunc unpad () { local sz,ii localobj v1
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
v1=info.get("pads")
for ii=0,m-1 cob.v[ii].resize(v1.x[ii])
return v1
}
//** size() -- return num of vectors and size of each vector
func size () { local ii,sz,fl,sum
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (m==0) { print "0 x 0" return 0 } // empty
sz=cob.v.size fl=0
for ii=1,m-1 if (cob.v[ii].size!=sz) {fl=ii break}
if (numarg()==1) {
if ($1==2) {
tog("DB") sum=0
printf("\t%d cols x %d rows",m,sum+=v.buffer_size)
for ii=1,m-1 printf(",%d",cob.v[ii].buffer_size)
if (out!=nil) {
printf("\nOUT:\t%d cols x %d rows",m,sum+=out.v.buffer_size)
for ii=1,m-1 printf(",%d",sum+=out.v[ii].buffer_size)
}
printf("\nApprox. usage: %g kB\n",sum*8/1e3)
} else if ($1==1 && fl && !noheader) { // warn about discrepant sizes
printf("%s size WARN: cols are not same length: %s:%d %d\n",this,s[fl].s,cob.v[fl].size,sz) }
} else { // print basic info when have no args
printf("%d cols x %d rows",m,cob.v.size)
if (fl) for ii=1,m-1 printf(",%d",cob.v[ii].size)
print ""
}
return cob.v.size
}
//** resize(#cols[,#rows]) -- augment or dec the number of vectors
// resize("LABEL1","LABEL2",...)
// resize("LABEL1",VEC1,"LABEL2",VEC2) ... put on some vecs of same size
// resize("COL1","COL2"...) if these col names already exist just make a new copy of col
// resize(NQS) -- a horizontal 'append'
func resize () { local oldsz,newsz,i,ii,jj,kk,vsz,na,appfl,o1m,padfl
cob=this padfl=0
na=numarg()
vsz=-1
if (argtype(na)==2) { i=na
if (strcmp($si,"PAD")==0) { padfl=1 na-=1 }
}
if (na==1) {
if (argtype(1)==0) {
appfl=0
if ($1<0) newsz=m+$1 else newsz=$1
} else if (argtype(1)==2) {
newsz=m+1 appfl=2
} else if (argtype(1)==1) { // an NQS
if (size(1)!=$o1.size(1)) {
printf("NQS resize(NQS) warning: rows differ %d %d\n",size(1),$o1.size(1))}
o1m=$o1.m
newsz=m+o1m
appfl=3
}
} else {
if (argtype(1)==0 && argtype(2)==0) {
newsz=$1 appfl=0
vsz=$2
} else if (argtype(1)==2 && argtype(2)==2) {
newsz=m+na appfl=2
} else {
if (int(na/2)!=na/2) { printf("%s Resize ERR: require even # of args",this) return -1}
newsz=m+numarg()/2
appfl=1
}
}
oldsz=m
if (m==newsz) {
if(verbose) printf("No resize -- same size: %s\n",this)
return m
} else if (newsz>m) {
tmplist.remove_all vlist.remove_all
for ii=0,m-1 {
tmplist.append(v[ii]) tmplist.append(s[ii])
tmplist.append(out.v[ii])
}
objref v[newsz],s[newsz]
if (isassigned(out)) out.resize2(newsz) // create vectors for .out
jj=-1
for ii=0,m-1 {
v[ii]=tmplist.object(jj+=1) out.s[ii]=s[ii]=tmplist.object(jj+=1)
out.v[ii]=tmplist.object(jj+=1)
}
for ii=m,newsz-1 {
v[ii]=new Vector() out.s[ii]=s[ii]=new String()
out.v[ii]=new Vector()
}
out.m=m=newsz
tmplist.remove_all
} else {
for (ii=m-1;ii>=newsz;ii-=1) { out.v[ii]=v[ii]=nil out.s[ii]=s[ii]=nil }
out.m=m=newsz
}
x.resize(m) x.fill(0) fcd.resize(m)
out.x.resize(m) out.x.fill(0) out.fcd=fcd
if (vsz>=1) for ii=0,m-1 v[ii].resize(vsz)
if (appfl==1) { // append
for (ii=1;ii<=na;ii+=2) { i=ii
if (argtype(i)!=2) { printf("%s RESIZE ERR: arg %d should be str\n",this,i) return -1}
s[oldsz+(ii-1)/2].s=$si i+=1
if (argtype(i)==0) {
if ($i>0) v[oldsz+(ii-1)/2].resize($i)
} else if (argtype(i)==1) {
v[oldsz+(ii-1)/2].copy($oi)
} else { printf("%s RESIZE ERR2: arg %d should be num or obj\n",this,i) return -1}
}
} else if (appfl==2) {
for (i=1;i<=na;i+=1) {
if (argtype(i)!=2) { printf("%s RESIZE ERR3: arg %d should be str\n",this,i) return -1}
tstr=$si
if ((jj=fi(tstr,"EXACT"))!=-1) {
while (fi(tstr,"EXACT")!=-1) sprint(tstr,"%s0",tstr) // find unique name
}
kk=oldsz+i-1
s[kk].s=tstr
if (jj>=0) {
if (fcd.x[jj]==1) {
if (verbose) printf("NQS::Resize: converting OBJ Col '%s' to DBL Col '%s'\n",$si,tstr)
v[kk].resize(v[jj].size)
for ii=0,v[jj].size-1 v[kk].x[ii]=oform(fcdo.o(v[jj].x[ii]))
} else {
if (verbose) printf("NQS::Resize copying Col %s to %s\n",$si,tstr)
v[kk].copy(v[jj])
}
}
}
} else if (appfl==3) {
for i=0,o1m-1 {
tstr=$o1.s[i].s
while (fi(tstr,"NOERR")!=-1) sprint(tstr,"%s0",tstr)
s[oldsz+i].s=tstr
v[oldsz+i].copy($o1.v[i])
}
}
chk()
if (padfl) pad()
cob=this
return m
}
// for resizing the vector for .out
proc resize2 () { local newsz
newsz=$1
objref v[newsz],s[newsz]
}
// grow(NQS) append NQS of same size to this one
func grow () { local ii
if (m==0) { cp($o1)
} else if (m!=$o1.m) { printf("%s,%s off different size: %d %d\n",this,$o1,m,$o1.m) return 0
} else if (eqobj(cob,out)) {printf("%s ERR: run grow on full db\n",this) return 0.
} else for ii=0,m-1 v[ii].append($o1.v[ii])
return v.size
}
//** keepcols("LABEL1",...)
func keepcols () { local i,fl
scr.resize(0)
for i=1,numarg() {
if (argtype(i)==2) {
if ((fl=fi($si))==-1) return -1
} else fl=$i
scr.append(fl)
}
for (i=m-1;i>=0;i-=1) if (! scr.contains(i)) delcol(i)
return m
}
//** delcol("LABEL1"[,"LABEL2",...])
func delcol () { local ii,i,a localobj v1
tog("DB") // start at full db
a=allocvecs(v1)
if (argtype(1)==1) {
v1.copy($o1)
} else for i=1,numarg() {
if (argtype(i)==2) { if ((fl=fi($si))==-1) {dealloc(a) return -1} } else fl=$i
v1.append(fl)
}
v1.sort v1.reverse // get rid of last ones first
for i=0,v1.size-1 { fl=v1.x[i]
if (fl>m-1 || fl<0) { printf("%s ERR: delcol OOB:%d\n",this,fl) dealloc(a) return -1 }
for (ii=fl;ii<m-1;ii+=1) {
v[ii]=v[ii+1] s[ii]=s[ii+1]
out.s[ii]=s[ii+1]
}
v[m-1]=nil s[m-1]=nil
out.v[m-1]=nil out.s[m-1]=nil
// if ((x=fcd.x[fl])!=0) {} // ideally should go through and remove all objs or strs
x.remove(fl) fcd.remove(fl)
m -= 1
}
out.m=m
chk()
dealloc(a)
return m
}
//** delrow(#)
func delrow () { local ii,jj,kk
if (numarg()==1) {
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
kk=$1
if (kk<0 || kk>=cob.v.size) {printf("delrow %d OOR (%d)\n",kk,cob.v.size-1) return -1}
for ii=0,m-1 cob.v[ii].remove(kk)
} else { // remove selected
tog("DB")
if (ind.size>1) {
sprint(sstr,"Remove %d rows from main table?",ind.size)
if (!batch_flag) {
if (!boolean_dialog(sstr,"OK","Cancel")) { print "Cancelled" return -1 }
} else {
printf("Removing %d rows from main table.",ind.size)
}
}
for ii=0,m-1 for (jj=ind.size-1;jj>=0;jj-=1) { kk=ind.x[jj]
v[ii].remove(kk)
}
}
return v.size
}
//** getrow(#[,vec])
// getrow("COL",val[,vec]) // return 1st row where "COL" is val
obfunc getrow () { local i,ii,ix,fl,flag localobj v1
if (argtype(2)==0) { // fetch first matching row according to arg
if (argtype(1)==2) fl=fi($s1) else fl=$1
if (fl==-1) return
if (numarg()==3) v1=$o3 else v1=new Vector()
v1.resize(m)
v[fl].fetch($2,vl,v1)
} else {
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
ix=$1 i=2
if (argtype(i)==1) {v1=$oi i+=1} else v1=new Vector()
v1.l2p(cob.vl,ix)
for (ii=0;argtype(i)!=-1 && ii<v1.size;{i+=1 ii+=1}) if (argtype(i)==3) $&i=v1.x[ii]
}
return v1
}
//** getcol("name") getcol("name",1) returns pointer
// getcol("name"[,VEC]) copies to VEC
// getcol("name",0) -- copies to new vector and returns it
obfunc getcol () { local a,fl,ii localobj v1,vo,l
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (argtype(1)==2) fl=fi($s1) else fl=$1
if (fl==-1) return nil
v1=vo=cob.v[fl] // default returns pointer
if (fcd.x[fl]==1) {
if (oform(fcdo.o(vo.x[0]))==NOP) {
printf("NQS getcol Warning: returning indices for an object field\n")
} else if (oform(fcdo.o(vo.x[0]))==OK) {
l=new List()
for ii=0,vo.size-1 l.append(fcdo.o(vo.x[ii]))
return l
} else {
v1=new Vector(vo.size)
for ii=0,vo.size-1 v1.x[ii]=oform(fcdo.o(vo.x[ii]))
if (argtype(2)==1) {$o2.copy(v1) v1=$o2}
}
} else if (argtype(2)==0) {
if ($2==0) v1=vo.c
} else if (argtype(2)==1) { // copy into a preexisting vector
v1=$o2
v1.copy(vo)
}
return v1
}
//** getsel("name"[,vec]) returns the select(-1,...) values
obfunc getsel () { local ii,fl localobj v1
if (eqobj(cob,out)) printf("NQS WARNING: getsel() called after full select()\n")
if (argtype(1)==2) fl=fi($s1) else fl=$1
if (fl==-1) return v1
if (numarg()<2) v1=new Vector(ind.size) else {v1=$o2 v1.resize(ind.size)}
for ii=0,ind.size-1 v1.x[ii]=v[fl].x[ind.x[ii]]
return v1
}
//** renamecol("LABEL1","NEWNAME") -- rename column
func renamecol () { local oldsz
if (argtype(1)==2) {
if ((fl=fi($s1))==-1) return 1
} else fl=$1
s[fl].s=$s2
out.s[fl].s=$s2
return 1
}
//** renamecols("LABEL1","LABEL2"...) -- rename all column
proc renamecols () { local oldsz,i
if (numarg()<m) printf("Renaming only %d/%d cols\n",numarg(),m)
for i=1,numarg() s[i-1].s=$si
}
//** sv(FNAME[,APPEND]) save the NQS
// to sv selected -- NQS.select(...) NQS.cp(NQS.out,1) NQS.sv()
proc sv () { local i,j,cd,cd1,vers,a,aflag,nx,no,ns,svinfo localobj xo,v1,v2
aflag=cd1=0 // flags cd1=1 -- no single value vec compression;
if (eqobj(cob,out) && verbose) printf("==== WARNING: Saving selected only ====\n")
a=allocvecs(v1,v2)
if (numarg()>0) file=$s1 else aflag=2
if (numarg()>=2) aflag=$2
if (numarg()>=3) cd1=$3 // 1:flag for not compressing
if (aflag==2) { // will just continue saving in the current file
if (!tmpfile.isopen()) {printf("%s.sv() ERRA - attempt to append but no file open\n",this) return}
} else if (aflag==1) { tmpfile.aopen(file)
} else {
if (tmpfile.ropen(file)) {
if (batch_flag) {
printf("NQS sv WARNING overwriting %s\n",file)
} else if (!boolean_dialog("File exists","Overwrite","Cancel")) {
print "Cancelled" return
}
}
if (! tmpfile.wopen(file)) { printf("%s: can't open file\n",this) return }
}
v1.resize(m) v1.fill(0)
// will be saved without full vectors
if (cd1==0) for i=0,m-1 if (cob.v[i].ismono(0) && cob.v[i].size>10) {
cd1=2 // 2 flag for using compression
v1.x[i]=1
}
if (isassigned(fcdo)) foc=fcdo.count else foc=-1
vers=version(1) // will assist for identifying file type if change format in future
// dump info
svninfo=nx=no=ns=0
for ii=0,info.sz-1 {
if(info.x[ii]!=ERR) nx+=1
if(info.o[ii]!=nil) { xo=info.o[ii]
if (isojt(xo,v)) no+=1 else printf("NOT SAVING info %s\n",xo) }
}
ns=(sfunc.len(info.s)>0)+(sfunc.len(info.t)>0)+(sfunc.len(info.u)>0)+(sfunc.len(info.v)>0)
if (nx>0 || no>0 || ns>0) { svinfo=1 if (verbose) {
printf("%s.sv() WARN: saving info but ... 1.assumed sequential; 2. no labels:%d %d %d\n",\
this,nx,no,ns) }} else svinfo=0
cd=mkcodf(cd1,noheader,svinfo,vers) // stuff flags in 1 place
savenums(m,fcds.count,(cnt=fcd.count(-1)),foc,size(1),cd,vers,0,0) // extra for codes
wrvstr(file) wrvstr(comment)
if (!noheader) for i=0,m-1 wrvstr(s[i].s)
if (svinfo) {
savenums(nx,no,ns)
if (nx>0) savenums(&info.x,nx)
for ii=0,no-1 {xo=info.o(ii) if (isojt(xo,v)) xo.vwrite(tmpfile) }
if (ns>0) wrvstr(info.s) if (ns>1) wrvstr(info.t)
if (ns>2) wrvstr(info.u) if (ns>3) wrvstr(info.v)
}
fcd.vwrite(tmpfile)
for i=0,fcds.count-1 wrvstr(fcds.object(i).s)
for i=0,foc-1 {
if (isojt(fcdo.object(i),v)) {
fspitchar(1,tmpfile) // 1 for vector
fcdo.o(i).vwrite(tmpfile)
} else if (isojt(fcdo.object(i),this)) {
fspitchar(2,tmpfile) // 2 for NQS
fcdo.o(i).sv()
} else {
printf("NQS:sv() WARNING: Can't save obj %s for %s\n",fcdo.o(i),this)
fspitchar(0,tmpfile) // 0 for nil
}
}
if (cnt>0) for i=0,fcd.size-1 if (fcd.x[i]==-1) {
savenums(fcdl.object(i).count)
for j=0,fcdl.object(i).count-1 wrvstr(fcdl.object(i).object(j).s)
}
for i=0,m-1 {
if (cd1==2 && v1.x[i]==1) {
savenums(-1e9,cob.v[i].size,cob.v[i].x[0])
} else if (fcd.x[i]==CODTY) {
cob.v[i].vwrite(tmpfile,4) // must save CODE fully
} else {
cob.v[i].vwrite(tmpfile,svsetting)
}
}
x.vwrite(tmpfile)
if (aflag!=2) tmpfile.close
dealloc(a)
}
//** rd(FNAME[,FLAG]) read format saved by sv()
// flag==2 - only read header
func rd () { local n,vers,hflag,cd,cd1,cd3,cd4,ii,oco,nx,no,ns,svinfo localobj v1,xo
hflag=0 cob=this
a=allocvecs(v1)
if (numarg()>=1) if (argtype(1)==2) {
if (!tmpfile.ropen($s1)) { printf("%s: can't open file %s\n",this,$s1) dealloc(a) return 0 }
} // else continue reading from current point in file
if (numarg()>=2) hflag=$2 // only read header
cnt=fc=foc=0
// backward compatible -- if only 2 vals then cnt=0, cd1-4 unused at present
n=readnums(&ii,&fc,&cnt,&foc,&v0sz,&cd,&svvers,&cd3,&cd4)
if (n==0) {dealloc(a) return 0}
if (n<9) v0sz=cd1=svvers=cd3=cd4=-1
if (svvers<640) {
cd1=cd noheader=cd3 svinfo=0
} else {
uncodf(cd,&cd1,&noheader,&svinfo,&vers)
if (vers!=svvers) printf("INT DECODE VERS ERR in NQS.rd(): %d %d\n",svvers,vers)
}
if (cd1==2 && hflag==1) printf("NQSrdWARN0: can't do partial reads on compressed: %s\n",$s1)
if (ii!=m) resize(ii)
rdvstr(file) rdvstr(comment)
if (sfunc.len(file)==0 && numarg()>0) file=$s1
if (!noheader) for i=0,m-1 rdvstr(s[i].s)
if (svinfo) {
readnums(&nx,&no,&ns)
if (nx>0) readnums(&info.x[0])
for ii=0,no-1 {info.o(ii)=new Vector() info.o(ii).vread(tmpfile) }
if (ns>0) rdvstr(info.s) if (ns>1) rdvstr(info.t)
if (ns>2) rdvstr(info.u) if (ns>3) rdvstr(info.v)
}
fcd.vread(tmpfile)
fcds.remove_all
if (isassigned(fcdl)) fcdl.remove_all
for i=0,fc-1 { fcds.append(Xo=new String()) rdvstr(Xo.s) }
if (foc>=0) { fcdo=new List() out.fcdo=fcdo }
for i=0,foc-1 {
oco=fgchar(tmpfile)
if (oco==1) {
fcdo.append(Xo=new Vector())
Xo.vread(tmpfile)
} else if (oco==2) {
fcdo.append(Xo=new NQS())
Xo.rd()
} else if (oco==0) {
printf("NQS:rd() WARNING: Nil being read for %s\n",this)
} else {
printf("NQS:rd() ERROR: unrecognized char %d for %s\n",oco,this)
}
}
if (cnt>0) for i=0,fcd.size-1 if (fcd.x[i]==-1) {
readnums(&cnt)
Yo=new List()
for j=0,cnt-1 {Xo=new String() Yo.append(Xo) rdvstr(Xo.s)}
useslist(i,Yo)
}
if (hflag==1) { // v0sz will tell size of all vectors
tell=tmpfile.tell
tmpfile.seek(0,2)
tellend=tmpfile.tell()
if (v0sz==-1) printf("%s: rd header: can't do seeks since v's not same size:%s\n",this,file)
dealloc(a)
return v0sz
} else {
v0sz=-1 // indicates that everything has been read in
for i=0,m-1 {
v[i].vread(tmpfile)
if (v[i].size>2) if (v[i].x[0]==-1e9) {
ii=v[i].x[2]
v[i].resize(v[i].x[1])
v[i].fill(ii)
}
}
x.vread(tmpfile)
}
if (foc==0) for ii=0,fcd.size-1 if (fcd.x[ii]==1) v[ii].fill(-1) // clear obj pointers
out.cp(this,0) // leave vectors empty
chk()
dealloc(a)
return 1
}
//** rdpiece() read a section of each vector
func rdpiece () { local ii,ix,end,jump,loc,bswap
ix=$1
if (numarg()>=2) bswap=$2 else bswap=0
tmpfile.seek(tell+8) // start of first one
if (ix<0) {printf("%s:rdpiece ERR: no room: neg index\n",this) return 0}
if (ix*chunk>v0sz) return 0
if ((ix+1)*chunk>v0sz) end=v0sz-ix*chunk else end=chunk
for ii=0,m-1 {
loc=tell+8+ii*(v0sz*4+8)+ix*4*chunk
tmpfile.seek(loc)
if (loc+end*4>tellend){printf("%s:rdpiece ERRA: ran out: %d %d",this,loc+end,tellend) return 0}
v[ii].fread2(tmpfile,end,3+bswap)
}
return 1
}
// rddif(filename) reads a .dif (data interchange format) file as can be exported from eg Excel
// NB to save to .dif from ooffice use File->Save as
// to save other than sheet#1 need to delete first (select didn't work): Edit->Sheet->Delete
proc rddif () { local a,ii,x,done,val,sz localobj oq,st
st=new String2()
empn=0 fln_lnum=1
file=$s1
tmpfile.ropen(file)
fln(3,st) // move forward 3 to pick up name
sprint(comment,"'%s' from %s",st.s,file)
x=fln(2,st) resize(x)
x=fln(3,st) clear(x) // should be 1 larger in size, fill with ERR
fln("BOT",st,0) // look for precise string "BOT"
for ii=0,m-1 {
fln(2,st)
if (sfunc.len(st.s)>0) { repl_mstr(st.s," ","_") s[ii].s=st.s
} else s[ii].s="UUEMPUU" // code for later
}
fln("BOT",st,0)
// now pick up line pairs which are "text"\n1,0 OR 0,val\nV
done=0
while (!done) {
for ii=0,m-1 {
x=fln(1,st) val=x st.t=st.s // don't need to save st.t?
y=fln(1,st)
if (strcmp(st.s,"V")==0) {
v[ii].append(val)
} else if (sfunc.len(st.s)==0) { // empty
if (fcd.x[ii]==2) { v[ii].append(0) // empty string
} else v[ii].append(OK)
} else { // a string
if (fcd.x[ii]!=2) { printf("STRDEC:%d,%d ",ii,v[ii].size+1) fcd.x[ii]=2 }
sval=st.s
v[ii].append(newval(2,ii))
}
// print val,st.t,x,st.s
}
fln(2,st)
if (strcmp(st.s,"EOD")==0) { done=1 break }
if (strcmp(st.s,"BOT")!=0) {
printf("ERR: should be at BOT at line#: %d %d %s\n",_lnum,v.size,st.s)
done=1 break // done is redundant
}
}
sz=v.size
for (ii=m-1;ii>=0;ii-=1) { // check the empty columns
if (strcmp(s[ii].s,"UUEMPUU")==0) {
if (v[ii].count(OK)!=sz) {
printf("WARN: nonempty vector with empty header for col %d\n",ii)
sprint(s[ii].s,"COL%d",ii)
} else delcol(ii)
}
}
}
// read a .atf file which is the ascii version of a pCLAMP .abf file
proc rdatf () { local ii,rows,cols localobj st,v1,v2
st=new String2() v1=new Vector() v2=v1.c
fln_lnum=1
file=$s1 rows=file_len($s1) tmpfile.ropen($s1)
fln(2,st)
sscanf(st.s,"%*d%*[^0-9]%d",&cols)
resize(cols)
clear(rows)
fln("CURRENT",st)
repl_str(st.s,"CURRENT","") repl_mstr(st.s,"\t",",") sfunc.right(st.s,1)
split(st.s,v1) info.o=v1
fln("^Time",st)
if (v1.size!=cols-1) {printf("rdatf() discrepancy in %s: %d %d\n",$s1,v1.size,cols-1) return }
s[0].s="t"
for ii=1,m-1 {
sprint(s[ii].s,"pA%d",v1.x[ii-1])
if (strm(s[ii].s,"-")) repl_str(s[ii].s,"-","m")
}
while (tmpfile.gets(st.s)!=-1) {
fln_lnum+=1
repl_mstr(st.s,"\t",",")
split(st.s,v2)
if (v2.size!=m) printf("rdatf() prob at line %d: %s\n",fln_lnum-1,st.s) else append(v2)
}
}
//** func rdcols()
// reads columns of ascii with optional labels at the top
// still won't read strings -- prob not worth fixing any more
// -- may want to go back to v617 for this
func rdcols () { local i,ii,cols,li,errflag,num,hflag,loc localobj fi,st
hflag=1 errflag=0 st=new String2()
if (argtype(1)==2) {
fi=tmpfile st.s=$s1 loc=0 tflg=0
if (! fi.ropen(st.s)) { printf("\trdcols ERR0: can't open file \"%s\"\n",st.s) return 0}
} else {fi=$o1 fi.getname(st.s) hflag=0 loc=fi.tell() tflg=1}
if (fcd.count(2)+fcd.count(0)!=m) {printf("\trdcols ERRA: only rd strs and dbls\n") return 0}
if (fi.scanstr(sstr)==-1) {printf("\trdcols ERR1: file \"%s\"\n",st.s) return 0}
if (fcd.count(2)==0 && !isnum(sstr)) hflag=1 else hflag=0 // hflag=0 -> no header
if (numarg()>1) { // names of columns
resize(numarg()-1)
for i=2,numarg() sethdrs(i-2,$si)
if (hflag) {
printf("Header in file %s: %s vs %s\n",st.s,sstr,s[0].s)
hflag=2
}
} else if (!hflag) printf("No Header read for %s\n",st.s)
cols=0
if (hflag==1) {
fi.seek(0)
fi.scanstr(sstr)
while (! isnum(sstr)) {
cols+=1
resize(sstr)
fi.scanstr(sstr)
}
fi.seek(0) fi.gets(sstr) loc=fi.tell
ncols=cols
} else {
ncols=fcd.count(0) // assume that NQS was set up ahead
cols=fcd.size
if (cols==0) {
fi.seek(0)
fi.gets(sstr)
ncols=cols=count_substr(sstr,"[-+0-9.][-+0-9.eE]*")
if (cols==0) printf("NQS::ERR2A reading first line: %s (%s)\n",sstr,this)
resize(cols)
fi.seek(0)
}
}
li=file_len(st.s)
if (hflag || tflg) li-=1 // hack -- assuming that threw away one line
printf("%d cols; %d lines of data in %s.\n",cols,li,st.s)
fi.seek(loc) // back to top
// WARN: this will screw up if numbers are to be included as strings
if (fcd.count(2)==0) {
num=scr.scanf(fi,li*ncols) // note that this will skip over non-nums
if (num!=li*ncols) { // err not reached since scanf dumps out
printf("WARNING: expected %d vals; found %d\n",li*ncols,num) errflag=3 }
if (fi.scanstr(sstr)>-1) {
printf("WARNING: %s found after reading in %d vals\n",sstr,li*cols) errflag=4 }
}
fi.seek(loc)
for ii=0,cols-1 {
if (fcd.x[ii]>0) continue
v[ii].resize(li)
v[ii].copy(scr,0,ii,li*ncols-1,1,cols) // v[ii].mcol(scr,ii,cols)
}
if (fcd.count(0)!=m) {
fi.seek(loc) // need to pick up some strings
for ii=0,li-1 for jj=0,cols-1 {
if (fi.scanstr(st.t)==-1) {printf("ERR reading at %d\n",fi.tell()) errflag=5 return 0}
if (fcd.x[jj]==2) v[jj].append(newval(2,jj))
}
}
if (errflag) { printf("rdcols ERR%d\n",errflag) return 0 }
return cols
}
//** func rdcols2() -- goes line by line so as to handle cols with strings
func rdcols2 () { local i,ii,cols,li,errflag,num,loc,x,ln localobj fi,st,ol,sep
errflag=0 st=new String2() ol=new List() sep=new String()
if (argtype(1)==2) {
fi=tmpfile st.s=$s1 loc=0 tflg=0 i=2
if (! fi.ropen(st.s)) { printf("\trdcols2 ERR0: can't open file \"%s\"\n",st.s) return 0}
} else {fi=$o1 fi.getname(st.s) loc=fi.tell() tflg=1}
if (argtype(i=2)==2) sep.s=$si else sep.s="[ ]+"
if (strm(sep.s,"[^\\]\\|")) printf("WARNING: unescaped | (means OR) in separator '%s' for %s\n",sep.s,this)
if (fcd.count(2)+fcd.count(0)!=m) {printf("\trdcols2 ERRA: only rd strs and dbls\n") return 0}
if (fi.gets(sstr)==-1) {printf("\trdcols2 ERR1: file \"%s\"\n",st.s) return 0}
if (m==0) {printf("\trdcols2 ERR1A: NQS %s must be preinitialized for rdcols2\n",this) return 0}
ncols=fcd.count(0) cols=fcd.size() li=file_len(st.s)
chop(sstr) split(sstr,ol,sep.s) // check that first lline
if (ol.count!=cols) {printf("\trdcols2 ERR1B: %d != %d::",cols,ol.count)
for ii=0,ol.count-1 printf("%s;",ol.o(ii).s)
print "" return 0}
printf("%d cols; %d lines of data in %s.\n",cols,li,st.s)
fi.seek(loc) // back to top
for (ln=1;tmpfile.gets(sstr)!=-1;ln+=1) {
chop(sstr)
if ((num=split(sstr,ol,sep.s))!=cols) printf("rdcols2() PROBLEM (%d) on line %d: %s [%s]\n",num,ln,sstr,sep.s)
// for i=0,ol.count-1 printf("%s ",ol.o(i).s) print "" //
for ii=0,m-1 {
if (fcd.x[ii]==2) {
sval=ol.o(ii).s
v[ii].append(newval(2,ii))
} else {
sscanf(ol.o(ii).s,"%g",&x)
v[ii].append(x)
}
}
}
return cols
}
//** func svR([filename])
// saves in a format that can be read by my rdnqs.R program
func svR () { local ii,jj,cols,li,errflag,num
errflag=0
if (eqobj(cob,out) && verbose) printf(" *Selected* ")
if (numarg()==1) sstr=$s1 else {
sstr=file
repl_mstr(sstr,"\.nqs$",".nqR")
}
if (tmpfile.ropen(sstr)) if (!boolean_dialog("File exists","Overwrite","Cancel")) {
print "Cancelled" return 0 }
if (! tmpfile.wopen(sstr)) { printf("\tsvR ERR0: can't open file \"%s\"\n",sstr) return 0}
tmpfile.printf("%d\n",m)
for ii=0,m-1 tmpfile.printf("%s\n",s[ii].s)
for ii=0,m-1 cob.v[ii].vwrite(tmpfile)
tmpfile.close()
return ii
}
//** func svcols(filename)
// saves numeric columns for R -- read with aa=read.table("filename")
func svcols () { local ii,jj,cols,li,errflag,num
errflag=0
if (tmpfile.ropen($s1)) if (!boolean_dialog("File exists","Overwrite","Cancel")) {
print "Cancelled" return 0 }
if (! tmpfile.wopen($s1)) { printf("\tsvcols ERR0: can't open file \"%s\"\n",$s1) return 0}
sstr2="\t" // delimiter
for ii=0,m-1 tmpfile.printf("%s%s",s[ii].s,sstr2)
tmpfile.printf("\n")
for ii=0,size(1)-1 {
tmpfile.printf("%d%s",ii,sstr2)
for jj=0,m-1 {
getval(jj,v[jj].x[ii],ii)
tmpfile.printf("%g%s",nval,sstr2)
}
tmpfile.printf("\n")
}
tmpfile.close
return ii
}
//** join(nqs2,"PIVOT"[,"COLA",...])
// [selected fields of] nqs2 will be appended to this
// index field should only appear once in nqs2
func join () { local vn,vn1,vn2,i,ii,jj,kk,val localobj al,bl
al=new List() bl=new List()
if ((vn1=fi($s2))==-1 || (vn2=$o1.fi($s2))==-1) {
printf("NQS::join() %s not found in both %s %s\n",$s2,$o1,this) return -1 }
if (!v[vn1].ismono) { print "Sorting A..." sort(vn1) }
if (!$o1.v[vn2].ismono){print "Sorting B..." $o1.sort(vn2) }
if (!$o1.v[vn2].ismono(2)){ printf("Pivot B has repeats\n") return -1 }
scr.resize($o1.m) scr.fill(-1)
if (numarg()>2) for i=3,numarg() {
if ((vn=$o1.fi($si))==-1) return -1
if (fi($si,"NOERR")!=-1) sprint(tstr,"%sB",$si) else tstr=$si
scr.x[vn]=resize(tstr)-1 // index for this
} else for ii=0,$o1.m-1 if (! strcmp($o1.s[ii].s,$s2)==0) { // don't add pivot field
if ($o1.fcd.x[ii]!=0) {printf("%s:join ERRA not double field\n",this) return -1}
if (fi($o1.s[ii].s,"NOERR")!=-1) sprint(tstr,"%sB",$o1.s[ii].s) else tstr=$o1.s[ii].s
scr.x[ii]=resize(tstr)-1 // index for this
}
pad()
for jj=0,scr.size-1 { kk=scr.x[jj]
if (kk!=-1) { al.append(v[kk]) bl.append($o1.v[jj]) }
}
v[vn1].join($o1.v[vn2],al,bl)
return m
}
//** cp(NQS[,VEC_COPY]) copy 1 NQS to another
// default: VEC_COPY==1; side effect of NO_VEC_COPY is no fcd,fcds creation
proc copy () { if (numarg()==2) cp($o1,$2) else cp($o1) }
proc cpout () { // copy .out to this
cob=this
for ii=0,m-1 v[ii].copy(out.v[ii])
}
proc cp () { local ii,csz,veccp,outcp localobj o,oo
cob=this
csz=$o1.m
outcp=0
if (numarg()==2) veccp=$2 else veccp=1
if (m!=csz) if (isassigned(out)) resize(csz) else {
resize2(csz)
outcp=1
}
noheader=$o1.noheader
objl.remove_all
for ii=0,$o1.objl.count-1 { objl.append($o1.objl.object(ii)) }
file=$o1.file comment=$o1.comment
if (outcp) for ii=0,m-1 {
if (!noheader) s[ii]=up.s[ii]
v[ii]=new Vector()
} else for ii=0,m-1 {
if (!noheader) s[ii].s=$o1.s[ii].s
if (veccp) v[ii].copy($o1.v[ii]) // 2nd arg to not copy vectors
}
if (veccp==1) { // full copy
fcd.copy($o1.fcd)
for ii=0,$o1.fcds.count-1 fcds.append($o1.fcds.object(ii)) // strings not being copies
if (isobj($o1.fcdl,"List")) { fcdl=new List() out.fcdl=fcdl
for ii=0,$o1.fcdl.count-1 fcdl.append($o1.fcdl.object(ii)) }
if (isobj($o1.fcdo,"List")) { fcdo=new List() out.fcdo=fcdo
o=$o1.fcdo
for ii=0,o.count-1 {
if (isojt(o.o(ii),v)) { // a vector
oo=new Vector(o.o(ii).size) oo.copy(o.o(ii)) fcdo.append(oo)
} else if (isojt(o.o(ii),out)) { // a vector
oo=new NQS() oo.cp(o.o(ii)) fcdo.append(oo)
} else {
printf("Can't copy a %s\n",o.o(ii)) return
}
}
}
} else if (! isassigned(fcd)) { // use pointers for .out
fcd=$o1.fcd fcds=$o1.fcds fcdl=$o1.fcdl tmplist=$o1.tmplist
}
x.copy($o1.x) x.resize(m)
scr.copy($o1.scr) ind.copy($o1.ind)
}
//** eq(NQS) -- just check the vecs
func eq () { local ii,jj,af,ix,epsilon,sz localobj v1,v2,o,xo,yo
o=$o1
if (numarg()>=2) {
af=1
if ($2!=1) epsilon=$2 else epsilon=1e-5
} else af=0 // af is flag for approx eq
if (o.m!=m) { printf("# of cols differ %d vs %d\n",m,o.m) return 0 }
if (!noheader) for ii=0,m-1 if (strcmp(o.s[ii].s,s[ii].s)!=0) {
printf("%d col names differ: %s vs %s",ii,s[ii].s,o.s[ii].s) return 0 }
for ii=0,m-1 if (o.v[ii].size != v[ii].size) {
printf("%d col lengths differ: %d vs %d",ii,v[ii].size,o.v[ii].size) return 0 }
a=allocvecs(v1,v2)
if ((sz=info.sz)!=o.info.sz) printf("Info sz difference") else {
v1.resize(sz) v2.resize(sz) v1.d2v(&info.x) v2.d2v(&o.info.x)
if (!v1.eq(v2)) {printf("info x's differ:") vlk(v1) vlk(v2)}
for ii=0,sz-1 { xo=info.o[ii] yo=o.info.o[ii]
if (!isojt(xo,yo)) {printf("Different info objs at %d: %s %s\n",ii,xo,yo)
} else if (isojt(xo,v) || isojt(xo,this)) if (!xo.eq(yo)) {
printf("Different info objs at %d: %s %s %d %d\n",ii,xo,yo,xo.size,yo.size)}
}
xo=o.info
if (strcmp(info.s,xo.s)!=0 || strcmp(info.t,xo.t)!=0 || strcmp(info.u,xo.u)!=0 ||\
strcmp(info.v,xo.v)!=0) { printf("Different strings:\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",\
info.s,xo.s,info.t,xo.t,info.u,xo.u,info.v,xo.u) }
}
if (af) {
for ii=0,m-1 {
v1.copy(v[ii])
v1.sub(o.v[ii])
v1.abs()
if (v1.max>epsilon) {
ix=v1.max_ind
if (noheader) {
printf("%d cols differ: \n",ii,ix,v[ii].x[ix],o.v[ii].x[ix])
} else printf("%s cols differ: \n",s[ii].s,ix,v[ii].x[ix],o.v[ii].x[ix])
}
}
if (numarg()>=3) $o3.copy(v1)
} else for ii=0,m-1 if (! o.v[ii].eq(v[ii])) {
if (noheader) { printf("%d cols differ at ",ii)
} else printf("%s cols differ at ",s[ii].s)
for jj=0,v[ii].size-1 if (o.v[ii].x[jj] != v[ii].x[jj]) {
printf("element %d: %g vs %g",jj,v[ii].x[jj],o.v[ii].x[jj])
if (o.v[ii].x[jj]-v[ii].x[jj]<1e-5) {
printf("\n\tTry for approximately equal using flag: nq.eq(nq2,1)\n")}
return 0
}
}
if (! fcdseq(o)) return 0
if (! fcdoeq(o)) return 0
dealloc(a)
return 1
}
//** fcdseq() -- check that string lists are identical in two NQSs -- this is
// sufficient but not nec for comparing string columns for JOIN
// in order to use JOIN must share same fcds by setting up with strdec(NQS,...)
// (could break out separate lists for each str column -- tried in nqs.hoc220;
// but separate lists would be problem: two columns might require same indices if
// either could be used to for "JOIN" to another nqs
func fcdseq () { local ii,jj,cnt
cnt=fcds.count
if (eqobj(fcds,$o1.fcds)) {
printf("%s %s already share string list fcds\n",this,$o1)
return 1
}
if (cnt!=$o1.fcds.count) {
printf("DIFFERING (1) string lists (fcds) %d %d\n",fcds.count,$o1.fcds.count)
return 0
}
for ii=0,cnt-1 if (!strcmp(fcds.object(ii).s,$o1.fcds.object(ii).s)==0) {
printf("DIFFERING (2) string lists (fcds) %d:%s vs %s",ii,fcds.object(ii).s,$o1.fcds.object(ii).s)
return 0
}
if (numarg()==2) return 1 // just check fcds and not fcd and fcdl
if (! fcd.eq($o1.fcd)) {
printf("DIFFERING (3) col keys (fcd) ") vlk(fcd) vlk($o1.fcd)
return 0
}
if (! isassigned(fcdl) && isassigned($o1.fcdl)) {
printf("DIFFERING (4) uselists() string lists: absent in %s\n",this)
return 0
}
if (isassigned(fcdl)) {
if (! isassigned($o1.fcdl)) {
printf("DIFFERING (5) uselists() string lists absent in %s\n",$o1)
return 0
}
if (fcdl.count!=$o1.fcdl.count) {
printf("DIFFERING (6) uselists() list list counts %d vs %d",fcdl.count,$o1.fcdl.count)
return 0
}
for ii=0,fcdl.count-1 if (fcd.x[ii]==-1) {
if (!isobj(fcdl.object(ii),"List") || !isobj($o1.fcdl.object(ii),"List")) {
printf("DIFFERING (7) uselists() string lists (fcdl.obj) %d:%s vs %s",ii,\
fcdl.object(ii),$o1.fcdl.object(ii))
return 0
}
if (fcdl.object(ii).count != $o1.fcdl.object(ii).count) {
printf("DIFFERING (8) uselists() string lists counts (fcdl.obj) %d:%d vs %d",ii,\
fcdl.object(ii).count,$o1.fcdl.object(ii).count)
return 0
}
for jj=0,fcdl.object(ii).count-1 {
if (!strcmp(fcdl.object(ii).object(jj).s,$o1.fcdl.object(ii).object(jj).s)==0) {
printf("DIFFERING (9) uselists() string lists (fcdl.obj) %d,%d:%s vs %s",ii,jj,\
fcdl.object(ii).object(jj).s,$o1.fcdl.object(ii).object(jj).s)
return 0
}
}
}
}
return 1
}
//** fcdoeq() -- check that object lists are identical in two NQSs
func fcdoeq () { local ii,jj,cnt
if (! isassigned(fcdo) && ! isassigned($o1.fcdo)) return 1
if (! isassigned(fcdo)) {
printf("No object list in %s\n",this)
return 0
}
if (! isassigned($o1.fcdo)) {
printf("No object list in %s\n",$o1)
return 0
}
cnt=fcdo.count
if (cnt!=$o1.fcdo.count) {
printf("DIFFERING (1) object lists (fcdo) %d %d\n",fcdo.count,$o1.fcdo.count)
return 0
}
for ii=0,cnt-1 {
if (!isojt(fcdo.o(ii),$o1.fcdo.o(ii))) {
printf("DIFFERING (2) obj lists (fcdo) %s,%s (%s,%s)",fcdo.o(ii),$o1.fcdo.o(ii),this,$o1)
return 0
}
if (1) { // vector and nqs both use .eq() a vector: isojt(fcdo.o(ii),v)
if (! fcdo.o(ii).eq($o1.fcdo.o(ii))) {
printf("DIFFERING obj lists (fcdo) : differ %s,%s (%s,%s)",\
fcdo.o(ii),$o1.fcdo.o(ii),this,$o1)
return 0
}
}
}
return 1
}
//** strdec() -- declare these columns to be strings
func strdec () { local i,min
min=1
if (eqobj(cob,out)) {
printf("strdec() ERR: string fields can only be declared at top level\n") return 0}
if (numarg()==0) {
printf("strdec(NAME[,NAME1 ...])\n\tdeclare these field to be string fields\n") return 0}
out.fcd=fcd
if (argtype(1)==1) {
if (fcds.count>0) if (! fcdseq($o1,1)) { // just check fcds and not fcd, fcdl
printf("Pre-existing string lists differ; unable to join %s %s\n",this,$o1)
return 0
}
fcds=$o1.fcds // share string list to allow JOIN on a string field
min=2
}
for i=min,numarg() {
if (argtype(i)==2) fl=fi($si) else fl=$i
if (fl>-1) {
fcd.x[fl]=2
sval="`EMPTY'"
newval(2,fl) // don't want to put on more than one
}
}
return 1
}
//** fdec() -- declare these columns to be files with methods
func fdec () { local i,j,na
if (eqobj(cob,out)) {
printf("fdec() ERR: object fields can only be declared at top level\n") return 0}
na=numarg()
if (na==0 || na%3!=0) { printf("fdec(\"COLNAME\",\"METHOD\",\"PATH\"[,...])\n") return 0 }
out.fcd=fcd
for (j=1;j<=na;j+=3) {
i=j
if (argtype(i)==0) fl=$i else fl=fi($si)
if (fl==-1) return 0 else fcd.x[fl]=FUNTY
i+=1 s[fl].t=$si i+=1
if (sfunc.len($si)==0) { sprint(s[fl].t,"%s(\"",s[fl].t)
} else sprint(s[fl].t,"%s(\"%s/",$si,s[fl].t)
}
if (! isobj(fcdo,"List")) { fcdo=new List() out.fcdo=fcdo }
return 1
}
obfunc methget () { local fl,ix localobj o
fl=$1 ix=$2
if ((o=fcdo.o(ix).o)!=nil) return o
sprint(tstr,"tmpobj=%s%s\")",s[fl].t,fcds.o(fcdo.o(ix).x).s)
execute(tstr)
o=tmpobj // need to use external global tmpobj
fcdo.o(ix).o=o
return o
}
//** coddec() -- declare these columns to be coded
func coddec () { local i,min
min=1
if (eqobj(cob,out)) {
printf("coddec() ERR: CODE fields can only be declared at top level\n") return 0}
if (numarg()==0) {
printf("coddec(NAME[,NAME1 ...])\n\tdeclare these field to be code fields\n") return 0}
out.fcd=fcd
for i=min,numarg() {
fl=fi($si)
if (fl>-1) fcd.x[fl]=CODTY
}
return 1
}
//** deriv("COLA",...) generates a col with differences between each row value and preceding
proc deriv () { local fl,i
if (eqobj(cob,out)) { printf("Take deriv on whole set only\n") return }
for i=1,numarg() {
if (argtype(i)==0) fl=$i else fl=fi($si)
if (fl==-1) return
sprint(tstr,"%s'",s[fl].s) resize(tstr)
v[m-1].deriv(v[fl],1,1)
v[m-1].insrt(0,0)
}
}
//** odec() -- declare these columns to be objects
func odec () { local i
if (eqobj(cob,out)) {
printf("odec() ERR: object fields can only be declared at top level\n") return 0}
if (numarg()==0) {
printf("odec(NAME[,NAME1 ...])\n\tdeclare these field to be object fields\n") return 0}
out.fcd=fcd
for i=1,numarg() {
if (argtype(i)==0) fl=$i else fl=fi($si)
if (fl>-1) fcd.x[fl]=1
}
if (! isobj(fcdo,"List")) { fcdo=new List() out.fcdo=fcdo }
return 1
}
//** vdec() -- declare this column to be pointers to fcdv
func vdec () { local i
if (eqobj(cob,out)) {
printf("odec() ERR: vec ptr fields can only be declared at top level\n") return 0}
if (numarg()==0) {
printf("vdec(NAME[,NAME1 ...])\n\tdeclare these field to be vec ptr fields\n") return 0}
out.fcd=fcd
for i=1,numarg() {
if (argtype(i)==0) fl=$i else fl=fi($si)
if (fl>-1) fcd.x[fl]=VECTY // type for vec
}
if (! isobj(fcdv,"Vector")) { fcdv=new Vector(1e4) fcdv.resize(0) out.fcdv=fcdv }
return 1
}
//** mo([flag][,STAT1,...]) -- create global objectvars that point to the vectors
// first time use flag=1 to create new global objrefs, else just shift them
// flag=1 reassign objl but don't care if they already exist
// flag=2 don't print out the assignments
// flag=3 reassign objl; make sure they're unique
// flag=4 clear the vectors
// should we also create a set of global scalars to assign to in an iterator?
proc mo () { local ii,flag,i,hf
if (numarg()>=1) flag=$1 else flag=0 // flag:create objrefs
if (flag==1 || flag==3) {
if (objl.count>0) {
if (flag==3) if (batch_flag) {
printf("NQS mo(3) WARNING: Renamed object pointers.\n")
} else if (! boolean_dialog("New name object pointers?","YES","NO")) return
if (flag==1) if (batch_flag) {
printf("NQS mo(1) WARNING: Rassigned object pointers.\n")
} else if (! boolean_dialog("Reassign object pointers?","YES","NO")) return
}
objl.remove_all
for ii=0,m-1 if (sfunc.len(s[ii].s)>0) {
sstr=s[ii].s
repl_mstr(sstr,"[^A-za-z0-9]","",execstr)
sprint(sstr,"%sv",sstr)
if (flag==3) { // make sure it's unique
hf=0
while (name_declared(sstr)) { hf=1
printf("%s exists ... ",sstr)
sprint(sstr,"%sv",sstr)
}
if (hf) printf(" -> %s\n",sstr)
} else if (name_declared(sstr)) printf("%s reassigned: ",sstr)
printf("%s -> v[%d] (%s)\n",sstr,ii,s[ii].s)
sprint(execstr,"objref %s",sstr) execute(execstr)
sprint(execstr,"%s=%s",sstr,v[ii]) execute(execstr)
objl.append(new String(sstr))
}
sprint(execstr,"objref indv") execute(execstr)
sprint(execstr,"indv=%s",ind) execute(execstr)
} else {
if (objl.count==0) {
printf("Must create vecs with mo(1)\n")
} else if (objl.count>m) {
printf("STAT:mo ERR: wrong objref count in objl: %d vs %d\n",objl.count,m)
return
} else {
if (objl.count<m) {
printf("STAT:mo WARNING: unreferenced vecs for %s: refs %d<m %d\n",this,objl.count,m) }
for ii=0,objl.count-1 {
Xo=objl.object(ii)
if (flag==0) printf("%s -> %s.v[%d] (%s)\n",Xo.s,this,ii,s[ii].s)
if (flag==4) {sprint(execstr,"%s=nil",Xo.s)
} else sprint(execstr,"%s=%s",Xo.s,v[ii])
execute(execstr)
}
}
sprint(execstr,"objref indv") execute(execstr)
if (flag!=4) { sprint(execstr,"indv=%s",ind) execute(execstr) }
}
if (numarg()>1) for i=2,numarg() { // propagate the objl to other STATs
$oi.objl.remove_all
for ii=0,objl.count-1 $oi.objl.append(objl.object(ii))
}
}
//** unnan() gets rid of nans and inf's in numerical cols
proc unnan () { local ii
for ii=0,m-1 if (fcd.x[ii]==0) v[ii].unnan(0)
}
func version () { local x
if (numarg()==0) print nqsvers
sfunc.tail(nqsvers,",v [1-9]*.",tstr)
sscanf(tstr,"%d",&x)
return x
}
//* endtemplate
endtemplate NQS
//* array template -- an array pretending to be a list
begintemplate OARR
public oo,max,count,o,object,append,o2l,l2o,name,id
objref oo[1]
strdef name
proc init () {
max=$1 id=count=0
objref oo[max]
}
obfunc o () { // allow an array to pretend to be a list
if ($1<0 || $1>=max) {printf("OOB for OARR: %d >= %d\n",$1,max) return oo[0]}
if ($1>=count) printf("OARR WARNING: %d not assigned\n",$1)
return oo[$1]
}
obfunc object () { // allow an array to pretend to be a list
if ($1<0 || $1>=max) {printf("OOB for OARR: %d >= %d\n",$1,max) return oo[0]}
if ($1>=count) printf("OARR WARNING: %d not assigned\n",$1)
return oo[$1]
}
func append () {
if (count>max-1) {printf("OARR ERR: out of room: %d\n",max) return -1}
oo[count]=$o1 count+=1
return count
}
// copy array to a list
proc o2l () { local jj,min,mx
if (numarg()==3) {min=$2 mx=$3} else {min=0 mx=count}
for jj=min,mx $o1.append(oo[jj])
}
// copy list to array
proc l2o () { local jj,min,mx
if (numarg()==3) {min=$2 mx=$3} else {min=0 mx=$o1.count-1}
for jj=min,mx oo[jj]=$o1.o(jj)
}
endtemplate OARR
//* ancillary routines
//* sopset() returns symbolic arg associated with a string
proc sopset() { local i
for i=1,21 sops[i-1]=$i // AUGMENT TO ADD NEW OPSYM
}
sopset(ALL,NEG,POS,CHK,NOZ,GTH,GTE,LTH,LTE,EQU,EQV,EQW,EQX,EQY,NEQ,SEQ,RXP,IBE,EBI,IBI,EBE) // ADD NEW OPSYM NAME
proc sofset () {
for scase(XO,"ALL","NEG","POS","CHK","NOZ","GTH","GTE","LTH","LTE","EQU","EQV","EQW","EQX","EQY","NEQ","SEQ","RXP","IBE","EBI","IBI","EBE") for j=1,5 {
sprint(tstr,"%s%d=%s*%d",XO.s,j,XO.s,j+1)
execute(tstr)
}
}
sofset()
//** whvarg
func whvarg () { local ret
ret=-1
// ADD NEW OPSYM STRING
// ALL NEG POS CHK NOZ GTH GTE LTH LTE EQU EQV EQW EQX EQY NEQ SEQ RXP IBE EBI IBI EBE
for scase("ALL","<0",">0","CHK","!=0",">",">=","<","<=","===","EQV","EQW","EQX","EQY","!=","=~","~~","[)","(]","[]","()") {
if (strcmp($s1,temp_string_)==0) {ret=i1 break}
}
if (ret==-1) return ret else return sops[ret]
}
//** whkey(KEY,STR)
// place name of KEY from vecst.mod in temp_string_
func whkey () { local key
for scase("ALL","NEG","POS","CHK","NOZ","GTH","GTE","LTH","LTE","EQU","EQV","EQW","EQX","EQY","NEQ","SEQ","RXP","IBE","EBI","IBI","EBE") { // ADD NEW OPSYM NAME
sprint(tstr,"x=%s",temp_string_) execute(tstr)
if (x==$1) {
if (numarg()==2) $s2=temp_string_ else print temp_string_
break
}
}
return x
}
//** varstr(tstr) -- make a variable out of string by removing nonalphanumeric characters
func varstr () { local a,z,A,Z,a0,a9,a_,len,ii,sflag
a=97 z=122 A=65 Z=90 a0=48 a9=57 a_=95 // ascii codes
if (numarg()==2) sflag=1 else sflag=0
len = sfunc.len($s1)
for ({x=0 ii=0};ii<len && !((x>=a&&x<=z)||(x>=A&&x<=Z));ii+=1) { // allowed first char
sscanf($s1,"%c%*s",&x)
sfunc.right($s1,1)
}
if (ii==len) { printf("varstr() ERR: no useable characters") return 0}
sprint($s1,"%c%s",x,$s1)
for (;ii<=len;ii+=1) {
sscanf($s1,"%c%*s",&x)
sfunc.right($s1,1)
if ((x>=a&&x<=z)||(x>=A&&x<=Z)||(x>=a0&&x<=a9)||(x==a_)) { // allowed chars
sprint($s1,"%s%c",$s1,x)
}
}
if (sflag) {
sprint($s1,"strdef %s",$s1)
execute($s1)
sfunc.right($s1,7) // strip leading "strdef"
} else {
sprint($s1,"%s=0",$s1)
execute($s1)
sfunc.left($s1,sfunc.len($s1)-2) // strip the =0
}
return 1
}
strdef h1
h1="Select operators: \nALL <0 >0 CHK !=0 > >= < <= == EQV EQW EQX EQY != =~ ~~ [) (] [] ()\nALL NEG POS CHK NOZ GTH GTE LTH LTE EQU EQV EQW EQX EQY NEQ SEQ RXP IBE EBI IBI EBE\nmost are obvious; those that are not\nEQV: value equal to same row value another column (takes string arg)\nEQW: value found in other vector (takes vector or NQS arg)\nSEQ: string equal (takes string)\nRXP: regular expression comparison (takes string)\nIBE,EBI...: I=inclusive, E=exclusive for ranges\n"
proc nqshelp () {
if (numarg()==0) {
} else {
if (strcmp($s1,"select")==0) {
// ed=new TextEditor(h1,9,160) ed.map
printf("%s",h1)
}
}
}
proc delnqs () { local i
for i=1,numarg() nqsdel($oi)
}
proc nqsdel () { localobj iq,xo
if (isassigned($o1)) {
iq=$o1
if (isassigned(iq.fcdo)) for ltr(xo,iq.fcdo) if (isojt(xo,iq)) nqsdel(xo)
if (isassigned(iq.out)) {iq.out.cob=nil iq.out=nil}
iq.cob=nil iq=nil
}
if (!istmpobj($o1)) $o1=nil
tmpobj=nil
}
//* pmap() maps a function arg1 onto multiple args or a , sep string of args
proc pmap () { local i,na localobj st
st=new String()
na=numarg()
sprint(st.s,"%s(",$s1) // 1st arg is name of proc
for i=2,na sprint(st.s,"%s%s,",st.s,$si)
if (na>=2) chop(st.s)
sprint(st.s,"%s)",st.s)
execute1(st.s)
}
func fmap () { local i,na localobj st,o
st=new String() o=new DBL()
na=numarg()
sprint(st.s,"%s.x=%s(",o,$s1) // 1st arg is name of proc
for i=2,na sprint(st.s,"%s%s,",st.s,$si)
if (na>=2) chop(st.s)
sprint(st.s,"%s)",st.s)
execute1(st.s)
return o.x
}
// eg svnqss("filename","nq,nq[1],nq[2]")
proc svnqss () { local x localobj st,ol,xo
st=new String2() ol=new List()
st.s=$s2
split(st.s,ol,",")
for ltr(xo,ol,&x) {
sprint(st.s,"%s.tog(\"DB\") %s.info.s=\"%s\"",xo.s,xo.s,xo.s)
execute(st.s)
if (x==0) { sprint(st.s,"%s.verbose=0 %s.sv(\"%s\") %s.verbose=1",xo.s,xo.s,$s1,xo.s)
} else sprint(st.s,"%s.verbose=0 %s.sv(\"%s\",1) %s.verbose=1",xo.s,xo.s,$s1,xo.s)
execute(st.s)
}
}
obfunc rdnqss () { localobj xo,st,ol
xo=new NQS() st=new String2() ol=new List()
xo.rd($s1)
ol.append(xo)
xo=new NQS()
while (xo.rd) { ol.append(xo) xo=new NQS() }
delnqs(xo)
st.s=ol.o(0).info.s
print st.s
declare(st.s,"o[10]") // make default array of 10 of them if not there
for ltr(xo,ol) { printf("%s size ",xo.info.s) xo.size()
st.t=xo.info.s
if (strm(st.t,"\[[0-9]*\]")) { // do nothing for an object array
printf("Here's hoping that %s is predeclared; if not error here: \n\t\t",st.t)
} else if (name_declared(st.t)==2) {
sprint(st.s,"delnqs(%s)",st.t) execute(st.s)
} else {
sprint(st.s,"objref %s", st.t)
execute(st.s)
}
sprint(st.s,"%s=new NQS() %s=%s",st.t,st.t,xo)
execute(st.s)
}
return nil
}
//* bugs and missing features
// 1. for NQS, does resize work with object columns? i.e.
// > > nqs1 has an object column
// > > can i do nqs2.resize(nqs1) to add nqs1 to nqs2?
// > looks like I haven't bothered with that case (nqs.hoc_579:2188)
// 2. oc> for ii=2,3 nq[ii-2].resize(nq[ii]) -- meaningless err messages?
// (~/nrniv/place/load.hoc_54:60)
// NQS[48] fi ERR: regexp matches more than once: 1 spkstats.killp
// NQS[48] fi ERR: regexp matches more than once: 2 spkstats.prup