4.3BSD/usr/contrib/apl/lib/ngradesys

n*.KB	H	idn { id nam; sname; sum; n; v; index
  nam { ,nam
  sname {  ((1YRname),Rnam)Yname
  sum { +/v{^/sname=(Rsname)Rnam
  n { 0
  } (0=sum)/nfind
  } (1#sum)/mfind
  n { vI1
  } (^/((1URname)Ynam)=name[n;])/0
  L { ' ',' ','full name: ',name[n;]
  }0
nfind: L { 'name not found'
  } 0
mfind: L { 'ambiguous names'
  sname { v/[1]name
  } (0=^/^/((Rsname)Rsname[1;])=sname)/dfind
  L { ' ',(NJ(((1YRsname),1)R index { v/I1YRname)),':',' ',sname
getidx: n { 'Enter index of desired name: ' getnum '-'
  } (0=V/n=index,`1)/error
  } 0
dfind: L { ' ',' ',sname
  } 0
error: L { '*** illegal index, try again ***'
  } getidx
	dstatdstat x; z
  z { stat x
' '
' '
  'sample size          ';z[1]
  'maximum              ';z[2]
  'minimum              ';z[3]
  'range                ';z[4]
  'mean                 ';z[5]
  'variance             ';z[6]
  'standard deviation   ';z[7]
  'mean deviation       ';z[8]
  'median               ';z[9]
summarysummary; i
L{' '
L{'     score summary'
L{'  '
L { ((4+1URname),(`1+1YRlist)R4)fhead list
L { name,(5 0 NJ ((1YRname),1)RI1YRname),4 0NJ score
L { 3 1 R ' '
dropdrop ;nam;idx;mask
L { 'Enter names (one per line) end with an empty line.'
getname: L'{'name: '
  } (0=Rnam{L')/0
  idx { id nam
  } (0=idx)/getname
  L { ((4 + 1URname),(`1+1YRlist)R4)fhead list
  L { name[idx;],(5 0NJidx),4 0NJscore[idx;]
  L'{'ok? (y/n): '
  }('y'#'L)/nogo
  mask { (1YRname)R1
  mask[idx]{0
  name {mask/[1]name
  } ((`1YRssn)=0)/nossn
  ssn { mask/[1]ssn
  } ssnd
nossn: ssn { ((1YRname),0)R''
ssnd: } ((`1YRscore)=0)/noscore
  score { mask/[1]score
  } done
noscore: score { ((1YRname),0)R0
done: L{'drop completed'
  } getname
nogo: L { 'nobody dropped'
  } getname
	statz{stat x;r;max;min;mean;var;sd;md;med;mode;v;m;n
n{Rx
r{(max{x[n])-min{(x{x[|Hx])[1]
sd{(var{(+/(|x-nRmean{(+/x)%n)*2)%n-1)*0.5
md{(+/|x-nRmean)%n
med{0.5X+/x[(Sn%2),1+Dn%2]
z{n,max,min,r,mean,var,sd,md,med
	statname`H	number  maximum minimum range   mean    variancestd dev mean devmedian  	newstatstatscore { newstat data ;i
 statscore { (9,1URdata)R0
 i {1
next: statscore[;i]{stat data[;i]
 } ((1URstatscore) & i{i+1)/next
 statscore[1;]{+/[1]0#data
statsummarystatsummary 
L{' '
L{'      statistics summary'
L{' '
L { (11,(`2+1YRlist)R4) fhead 1 0Ulist
L { statname,4 0 NJ D newstat score
L { 3 1 R ' '
	newscorenewscore ;pos;i;mask;listn;p;tp;it
  L { 'current types are:'
  L { type
  L' { 'type ? '
  p { type find it { L'
  }(V/p)/oktype
  L { 'type not found'
  }0
oktype: tp { p/IRp
  pos { (tp<scoretype)I1
  mask { 1,(Rscoretype)R1
  mask[pos] { 0
  score { mask\score
  scoremax { mask\scoremax
  list { (1,mask)\[1]list
  scoretype { mask\scoretype
  scoretype[pos] { tp
  scoremax[pos] { 'scoremax ? ' getnum '.'
  listn { 2 0NJ+/,scoretype=scoretype[pos]
  list[pos+1;] { (1URlist)Yit,listn
CJ now input new scores
  i { 1
next: score[i;pos] { (name[i;],': ') getnum '-.'
  }((1YRname)&i { i+1)/next
  L { 'new score complete'
newnamenewname; nname; nssn
  L { 'enter names (one per line) end with an empty line.'
getname: L' { 'name: '
  }(0=Rnname{L')/done
  name { name addrow nname
  nssn { ''
  } (~askedssn)/addssn
  L' { 'ssn : '
  nssn { L'
addssn: ssn { ssn addrow nssn
  } getname
done: score { ((1YRname),`1YRscore)Yscore
  L { 'newname complete'
	analysisanalysis; i; mk; n 
n { 1YRname
means{ (n,1+1YRtype)R0
i{1
next: mk{ scoretype=i
 }done XI 0=V/,mk
means[;i]{ 100X(+/mk/score) % +/mk/scoremax
done: }((1YRtype) >= i{ i+1 )/next
means[;i]{ (+/(means[;Ii-1]X(n,Rweight)Rweight)) %+/weight

histgm title histgm data ; i;h;m50
m50 { 51 > S/data
data { S data%2-m50
h {51R0
i{0
loop: h[i+1] { +/data =i
}loop XI 50 & i {i+1
''
'              histogram of ',title
''
i { S/h
loop2: ' *'[1+ h&i]
}loop2 XI 0< i{i-1
'|----|----|----|----|----|----|----|----|----|----|'
}m50/low
'0   10   20   30   40   50   60   70   80   90   100'
}0
low:'0    5   10   15   20   25   30   35   40   45   50'

findp { list find item
p { ^/list=(Rlist)R(1URlist)Y item,'        '
	
printstatprintstat colnam;data
}(0=Rdata{ getcol colnam)/0
dstat data
	printstat0printstat0 colnam;data
}(0=Rdata{ getcol colnam)/0
data { (0#data)/data
dstat data
	getcoldata { getcol colnam;p
p { 1U list find colnam
}(~V/p)/snf
data { ,p/score
}0
snf:p { tlist find colnam
}(~V/p)/nnf
data {,p/means
}0
nnf:'column name ',colnam,' not found'
data { 0R0
	
printhistprinthist colnam;data
}(0=Rdata{ getcol colnam)/0
colnam histgm data
	printhist0printhist0 colnam;data
}(0=Rdata{ getcol colnam)/0
data { (0#data)/data
colnam histgm data
setupsetup ;i;tt;nname;wt
  } askedsetup/exit
  L{ 'enter the score types (one per line) end with an empty line.'
  type { 0 0 R' '
gettype: L' { 'type: '
  }next XI 0=Rtt { 'L
  type { type addrow tt
  }gettype
next: L{ 'enter the weights for each type'
  list{(1,Rlist)Rlist { (6S3+1URtype)Y'number'
  i { 1
  weight { (1YRtype)R0
nextweight: weight[i] { (type[i;],' = ') getnum '.'
  }nextweight XI (1YRtype)&i { i+1
  name { 0 0 R' '
  L { 'enter names (one per line) end with an empty line.'
getname: L' { 'name: '
  } next2 XI 0=Rnname { L'
  name { name addrow nname
  } getname
next2: score { ((1YRname),0)R0
  scoretype { 0R0
  scoremax { 0R0
  ssn { 0 0R0
  askedssn { 0
  subs { 0
  L { 'setup complete'
  askedsetup { 1
  } 0
exit: L { 'setup previously completed'
changechange;nam;stype;idx;ip;ic
  L' { 'Enter the item to be changed: '
  stype { L',' '
  ic { list find stype
  newtype { nwscore
  }(0#V/ic)/ok
  newtype { nwname
  }(^/stype=(Rstype)Y'name          ')/ok
  newtype { nwssn
  }(^/stype=(Rstype)Y'ssn           ')/ok
  L{'type not found'
  }0
ok:col { `1 + ic I 1
  L { 'Enter names (one per line) end with an empty line.'
getname: L' { 'name: '
  nam { L'
  } (0=Rnam)/0
  idx { id nam
  }(0=idx)/getname
  } newtype
nwscore: L{name[idx;],' - ',list[1+col;],'old score ',Bscore[idx;col]
  }(1#R ip{'new score: ' getnum '-.')/nc
  }(0>ip)/nc
  score[idx;col]{ip
 L { 'score change complete'
  }getname
nwname: L' { 'new name: '
  } (0=Rnam{L')/nc
  name { name addrow nam
  name[idx;] { name[1YRname;]
  name { name[I`1+1YRname;]
  L { 'name change complete'
  }getname
nwssn: L { name[idx;],' -  old ssn = ',ssn[idx;]
  L' { 'new ssn: '
  } (0=Rsin{L')/nc
  ssn[idx;] { 9Y (~sinE' -')/sin
  L { 'ssn change complete'
  }getname
nc: L{'no change'
  }getname

analstatsanalstats 
L {''
L {'   analysis statistics'
L { ''
tlist { type,[1](1URtype)Y'total'
L{(11,(`1+1YRtlist)R4) fhead tlist
L { statname,4 0 NJD newstat means
L { 3 1 R ' '

analprintanalprint; rank ;tlist
  tlist { type,[1](1URtype)Y'total'
  rank {  |V ,means[;1URmeans]
  L { ' '
  L { '   ranking of score totals'
  L { ' '
  L { ((3+1URname),(1YRtlist)R5) fhead ((1,1URtlist)R'rank    '),[1]tlist
  L { name[rank;],(4 0NJ(((Rrank),1)RIRrank)),5 1NJmeans[rank;]
  L { 3 1 R' '
anal466anal466; i; mk; ds; dt; dm; scoret; low 
CJ assume types hw, test and final
means{ ((Rnumber),1+1YRtype)R0
scoret { tscore score
  i{1
CJ for each student
loop: ds{ scoret[i;]
CJ homework
  mk { scoretype=1
  dt { mk/ds
  dm { mk/scoremax
CJ drop lowest homework
  low { (dtID/dt)#IRdt
  means[i;1]{(+/low/dtXdm)%+/low/dm
CJ tests (skip if none)
  }l1 XI ~V/mk{scoretype=2
  dt { mk/ds
  dm { mk/scoremax
  low { dtID/dt
  dt[low] { means[i;3] { S/dt[low],(scoretype=3)/ds
  means[i;2]{(+/dtXdm)%+/dm
  }loop XI (1YRmeans)&i{i+1
l1: means[;4]{ (+/(means[;1 2 3]X((Rnumber),Rweight)Rweight)) %+/weight
analprint
	tscoreres { tscore data; i; dt; mn; sd
CJ tscore computes the tscores for a vector
CJ or matrix <data>.
  res { (Rdata)R0
  i{1
  }loop XI 2=RRdata
  dt { data
  }l1
loop: dt { data[;i]
l1: mn { (+/dt)%Rdt
  sd { ((+/(dt-mn)*2)%`1+Rdt)*.5
  dt { 50 + 10 X (dt-mn)%sd
  }end XI 1=RRdata
  res[;i]{dt
  }loop X (1URres)&i{i+1
end: res{dt
	tsummarytsummary
L{' '
L{'     t-score summary'
L{'  '
L { ((4+1URname),(`1+1YRlist)R4)fhead list
L { name,(5 0 NJ numc),4 0NJ D tscore score

fheadr { f fhead list
r{((I+/f)E+\f)\O\ list

addrowr { mx addrow row; l
CJ add a new row to a matrix
l { (Rrow)S1URmx
r { (((1YRmx),l)Ymx),[1]lYrow
lgradelgrade 
CJ compute lettergrade
L{'enter cutoff values'
L{'        a    b    c    d'
cut { L
letter { ((1YRmeans),1)R'fdcba'[1++/means[;1URmeans]J.>cut]
alphabetizealphabetize;cols;order;alphabet
CJ alphabetize the name list and reorder the scores
  alphabet { ' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  cols { I 10 D Rname[1;]
  order { |H +/ (alphabetIname[;cols])X((Rname[;1]),10 D Rname[1;])RO|((Ralphabet)*cols)
  name { name[order;]
  score { score[order;]
  ssn { ssn[order;]
askssnaskssn ;i;sin
  } askedssn/enter
CJ ask for a ssn for each person in the name list
  i { 1
  ssn { ((Rname[;1]),9)R ' '
loop: L' { name[i;],': '
  sin { L', ' '
  ssn[i;] { 9Y (~ sin E ' -')/sin
  } ((1YRssn) & i { i+1)/loop
  L { 'ssn entry complete'
  askedssn { 1
  } 0
enter: L { 'ssn previously completed.'
	analgrinanalgrin;i;means;mk;ds;dt;dm;low;n;w
  n { 1YRname
  w { Rweight
  scoret { tscore score
  rank { means { (n,1+1YRtype)R0
  i { 1
  } subs/loop2
loop1: }enter1 XI ~V/mk{scoretype=i
  dm { mk/scoremax
  means[;i] { \O(+/(mk/scoret)X((n,Rdm)Rdm))%+/dm
  rank[;i] { \O|H|Gmeans[;i]
enter1: }loop1 XI (w&i{i+1)
  rank[;1+w] { \O|H|G(+/means[;1 2 3]X(n,w)Rweight)%+/weight
  } 0
loop2: ds { scoret[i;]
  mk { scoretype=1
  dt { mk/ds
  dm { mk/scoremax
  low { (dtID/dt)#IRdt
  means[i;1]{(+/low/dtXdm)%+/low/dm
  }enter2 XI ~V/mk{scoretype=2
  dt { mk/ds
  dm { mk/scoremax
  low { dtID/dt
  dt[low] { means[i;3] { S/dt[low],(scoretype=3)/ds
  means[i;2] { (+/dtXdm)%+/dm
  }loop2 XI (1YRmeans)&i{i+1
enter2: means[;4] { (+/(means[;1 2 3]X(n,w)Rweight)%+/weight
  rank { |H[1]|G[1]means
gringrin;ss;n
  ss { 'L,' '
  ss { 9Y(ss#'-')/ss
  n { (^/ssn=(Rssn)Rss)I1
  } (n$1YRssn)/ok
  L { 'invalid student id: ',ss
  } 0
ok: L { (13,(`2+1YRlist)R4) fhead 1 0 U list
  'max score', 4 0 NJ scoremax
  'raw score', 4 0 NJ score[n;]
  ' t  score', 4 0 NJ scoret[n;]
  ''
} (subs)/enter
  'Based on T scores but without using the substitution'
  '  algorithm (i.e. - no scores have been droped or replaced yet)'
enter: 'The total number of students in class is ',(3 0NJ `1URssn),'.'
  ''
  '        homework  test   final   total'
  'rank ', 8 0NJ rank[n;]
LlxK  77'type ''describe'' for a description of this workspace'		ssnprintssnprint function ;name
name { ssn
BJ function
askedsetup  
getnumnum { prompt getnum let;str
again: L' { prompt
  str { L'
  } (1<+/strE'.')/error
  } (1<+/strE'-')/error
  }goodnum XI ^/strElet,'0123456789'
error: L { '*** illegal number, try again. ***'
  }again
goodnum: num { BJ str
  } (1#R,num)/error
analizeanalize ;data;mean;didanal;tlist
  didanal { 0
  } ((RBN27)>1)/cont1
  L' { 'do you want names or ssn to be listed? (n/s): '
  } ('n'=1YL')/cont1
  ssnprint 'analize'
  }0
cont1: L' { 'do you want a score summary? (y/n): '
  } ('n'=1YL')/cont2
  summary
cont2:  L' { 'do you want raw score statistics? (y/n): '
  } ('n'=1YL')/cont3
  statsummary
cont3: L' { 'do you want a mean score summary? (y/n): '
  } ('n'=1YL')/cont7
  analysis
  analprint
  didanal { 1
cont7: L' { 'do you want individual score type rankings? (y/n): '
  } ('n'=1YL')/cont4
  } (didanal)/analcont2
  analysis
  didanal { 1
analcont2:  rankprint
cont4:  L' { 'do you want mean score statistics? (y/n): '
  } ('n'=1YL')/cont5
  } (didanal)/analcont1
  analysis
  didanal { 1
analcont1: analstats
cont5: L' { 'do you want histogram and statistics for any specific score? (y/n): '
  } ('n'=1YL')/0
  L { 'enter score types (one per line) end with an empty line.'
cont6: L' { 'type: '
  tp { L'
  } (0=Rtp)/0
  tlist { type,[1](1URtype)Y'total'
  data { (0#data)/data { getcol tp
  }(0=Rdata)/cont6
  tp histgm data
  L { 3 1 R' '
  L { (3R' '),'statistics of ',tp
  dstat data
  L { 3 1 R' '
  } cont6

rankprintrankprint;  av1; tlist
  tlist { type,[1](1URtype)Y'total'
  av1 { |H [1]|V [1]means
  L { ' '
  L { '   ranking for each score type'
  L { ' '
  L { ((3+1URname),(`1+1URav1)R4) fhead tlist
  L { name,4 0 NJav1
  L { 3 1 R' '
	describesynnnew apl score system                                               spring 1982

     an apl workspace is available which is designed to maintain and perform
analysis on a set of class grades.  the system is interactive in nature
allowing each user to select the set of functions suitable for his or her
needs.

     to obtain a frech copy of this system, type ')load ngradesys' after
entering apl.


setting up the system:
     to set the system up for a new class, the function 'setup' is used.
'setup' will respond by asking score types, score weights and student names.
names may be added or deleted at any time so an accurate name list is not
required to setup the system.

     the system is now setup.  save a copy of this setup workspace by typing
')save xxx'.  the workspace will be saved in the file xxx and may be loaded
in the future with the load command.  it is advisable to keep several backup
copies of an active grade workspace.


alphabetizing the name list:
     to enter new scores into the system efficiently it is best to have the
names alphabetized both in the system and the stack of new scores.  to
alphabetize the name list, type 'alphabetize'.  this will also reorder the
previously entered scores and ssn.  this function may be called any time after
the system is setup, ussually the function is called just after setup and
then each time a list of new names is added to the system.


entering the social security numbers (ssn):
     social security numbers can be entered by typing 'askssn'.  the system
will then prompt with a name and ask for the corresponding ssn.  this
sequence will continue until all ssn are entered.

entering a new set of grades:
     to enter a new score, type 'newscore' and you will be promted for the
grade type and the maximum possible score.  you will then be prompted for a
grade for each student.


adding and dropping students:
     to add a list of students, type 'newname'.  you will then be prompted
for a list of names.  enter each on a new line and then terminate the list
with a null line.  note, any old scores for these new students must be
inserted with the 'change' function. (described later)

     to drop a list of students, type 'drop'.  you will then be prompted
for a list of names.  enter each on a new line and then terminate the list
with a null line.  for each name entered, the system will display all grades
recorded for that student and then request confirmation that you still want
to drop the student.

changing names, scores, ssn:
     to change the spelling of a name, change the grade of a student or
correct a students ssn, type 'change'.  the function will then prompted
for the type of change needed.  the available types include 'name', 'ssn',
or one of the previously entered score types.  example, if the score types
available are 'hw', 'test', and 'quiz' and you are wanting to change the
second homework score, then enter 'hw 2' when prompted.  next, the function
will prompt for a name, the function verifies the name exists and then
prompts for the new data (the name, score or ssn).


analizing the scores:
     to analize the scores, type 'analize'.  this function will guide the
user through the analysis sequence.  just answer 'y' or 'n' for each of
the questions asked.
     the following analysis functions are available:
	 1) score summary - a list of raw scores for all score types and
		all students.  this is a convienent method of obtaining
		a hardcopy back up of all scores for the current class.
	 2) statistics summary - this function computes simple statistics
		each set of scores and prints out the results.
	 3) mean score summary - this computes the average percent grade
		for each grade type for each student and also the total
		percent grade based on the weights entered for the score
		types.
	 4) individual score rankings - this functions lists the students
		ordered by their rank of the total and their ranking for
		each score type is also listed.
	 5) mean score statistics - this function will compute simple
		statistics on the data generated by the mean score summary
		(function 3 above).
	 6) histogram and statistics for any specific score - this will
		generate simple statistics and a histogram for and
		individual score or any score type.  example: if 'hw' is
		a score type then 'hw' would generate data for the
		combined homeworks and 'hw 2' would generate data for
		just homework #2.


***** notes on using the system
     1) at no time should a function be interrupted midway through
	completion for this may cause inconsistencies in the workspace.
     2) the function which looks up names is able to look up a partial
	name and match it.  this implies that any time a name is required
	to be typed in, only the first few letters which unambiguously
	identify it are needed.  if a partial match is found, then the full
	name will be displayed so you can verify that the correct name was
	matched.  if you enter an ambiguous set of letters for a match,
	then the system will display all names which matched correctly.
     3) three digit scores and fractional scores upset the printing
	format of the score summary in analysis.  therefore it is best to
	limit maximum scores to 100.