1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
#!/usr/bin/awk
# The goal: uniform model documentation for all the models that ship with Apophenia.
#
# Doxygen provides pretty limited support for new types of documentation. It
# has the set of documentation types it does well, and that's that. So, this hack takes
# marks in the code and converts them into one documented enum block for each model,
# which Doxygen will then make beautiful.
#
# We'll start with something like
# /* \amodel apop_beta The Beta distribution.
#
# The beta distribution has two parameters and is restricted between zero and
# one. You may also find \ref apop_beta_from_mean_var to be useful.
#
# \adoc Input_format Any arrangement of scalar values.
# \adoc Parameter_format a vector, v[0]=\f$\alpha\f$; v[1]=\f$\beta\f$
# \adoc Settings None.
# */
# [...]
# /* \adoc Name <tt>Beta distribution</tt> */
#
# and write out something like:
#
# /**
# The Beta distribution.
#
# The beta distribution has two parameters and is restricted between zero and
# one. You may also find \ref apop_beta_from_mean_var to be useful.
#
# \hideinitializer \ingroup models */
# enum apop_beta {
# Name_x2x_, /**< <tt>Beta distribution</tt> */
# Input_format_x2x_, /**< Any arrangement of scalar values. */
# Parameter_format_x2x_, /**< a vector, v[0]=\f$\alpha\f$; v[1]=\f$\beta\f$ */
# RNG_x2x_, /**< Produces a scalar \f$\in[0,1]\f$. */
# };
#
# I added the _x#_x because doxygen merges enums together otherwise. There's a sed script
# (edit_group) that turns the enum documentation back into apop_model struct documentation.
#
# The awk script can enforce some uniformity, forcing the same order in things, and writing
# file named missing, that will list documentation bits that aren't present.
BEGIN {
IGNORECASE=1
doc_parts[1]="Name";
doc_parts[2]="Input_format"
doc_parts[3]="Prep_routine"
doc_parts[4]="Parameter_format"
doc_parts[5]="Estimate_results"
doc_parts[6]="Predict"
doc_parts[7]="RNG"
doc_parts[8]="CDF"
doc_parts[9]="Settings"
doc_parts[10]="Examples"
doc_part_count=10
model_count = 0
#print > "missing"
}
in_doc==1 && !/\\a[model|doc]/ {
if (sub("\\*/",""))
in_doc=0
items[current_model ":" current_item] = items[current_model ":" current_item] "\n" $0
}
/\\amodel/ {
sub("/\\*[ \\t]*","", $0) #cut /* (if any).
sub(".*\\\\amodel","", $0) #cut \amodel, now that I know what it is.
current_model = $1
in_doc=1
oh = $0
if (!models[current_model]) {
models[current_model]=current_model
model_count ++
}
sub(current_model,"", oh)
sub("\\*/","", oh)
sub("^[ \\t]","", oh)
current_item = "intro"
items[current_model ":" current_item] = oh
}
/\\adoc/ {
sub("/\\*[ \\t]*","", $0) #cut /* (if any).
sub("\\\\adoc[ \\t]*","", $0) #cut \adoc, now that I know what it is.
oh = $0
current_item = $1
sub($1,"", oh)
if (!sub("\\*/","", oh))
in_doc = 1
items[current_model ":" current_item] = oh
}
/\*\// { in_doc = 0 }
#the declaration [like apop_model new_model = {"new model", .p=prob, .score=deriv}; ] tells us which struct elements are actually used.
/apop_model[ \t]*[^ \t]*[ \t]*=.*{/ { in_decl=1 }
in_decl == 1 { cp = $0;
if (match(cp, "\"([^\"]*)\"")){
title= substr(cp,RSTART, RLENGTH)
gsub( "\"","",title)
items[current_model ":" "Name"] = "<tt>" title "</tt>"
}
while (match(cp, "\\.[^ \\t=]+[ \\t]*=")){
cp = substr(cp, RSTART+1, length(cp)-RSTART)
match(cp, "[ \\t=]")
items[current_model ":has" substr(cp, 0, RSTART-1)] = 1
cp = substr(cp, RSTART+1) #cut at the =, keep processing.
}
}
/\\}/ {in_decl=0;}
/}/ {in_decl=0;}
function onedot(name, isdefault){
dot = "<td class=\"altcolor\">M</td>"
defaultdot = "<td class=\"memitem\">D</td>"
if (isdefault)
class = "altcolor"
else
class = "memitem"
print "<tr><td class=\""class"\">" name "</td>";
if (isdefault)
print dot;
else
print defaultdot;
print "</tr>"
}
END {print "/** \\file */ /**\\defgroup models */"
model_no=0
for (m in models){
model_no++
#m = sorted_models[model_no];
print "\n/** "
if (items[m ":intro"])
print items[m ":intro"]
else
print "!!! Without an intro, " m " won't print\n" >> "/dev/stderr"
print " \\hideinitializer \\ingroup models */"
print "enum " m " {"
#apop_model apop_normal = {"Normal distribution", 2, 0, 0, .dsize=1,
# .estimate = normal_estimate, .log_likelihood = normal_log_likelihood,
# .score = normal_dlog_likelihood,
# .constraint = beta_1_greater_than_x_constraint, .draw = normal_rng,
# .cdf = normal_cdf, .predict = normal_predict};
#dot = "<td class=\"memitem\" >\\f$\\bullet\\f$</td>"
# print "model_specific_x" model_no "x_, /**< <table cellpadding=3px><tr><td><table class=\"memproto\">"
#
# onedot("Estimation", items[m ":hasestimate"])
# onedot("Prob.", items[m ":hasp"])
# onedot("Log likelihood", items[m ":haslog_likelihood"])
# onedot("RNG", items[m ":hasdraw"])
#
# print "</table></td><td><table class=\"memproto\">"
#
# onedot("Predict", items[m ":haspredict"])
# onedot("CDF", items[m ":hascdf"])
# onedot("Score", items[m ":hasscore"])
# onedot("Prep routine", items[m ":hasprep"])
#
# print "</table> </td></tr></table>*/"
for (i=1; i<=doc_part_count;i++){
part=doc_parts[i]
#print "processing", m, part, "\n" >> "/dev/stderr"
if (doc_parts[i]=="Estimate_results"){
print "postestimate_data_x" model_no "x_, /**< "
if (items[m ":estimated_data"])
print items[m ":estimated_data"]
else
print "Unchanged."
print "*/"
if (items[m ":estimated_parameters"]){
print "postestimate_parameters_x" model_no "x_, /**< "
print items[m ":estimated_parameters"]
print "*/"
}
if (items[m ":estimated_parameter_model"]){
print "postestimate_parameter_model_x" model_no "x_, /**< "
print items[m ":estimated_parameter_model"] "</td></tr>"
print "*/"
}
if (items[m ":estimated_info"]){
print "postestimate_info_x" model_no "x_, /**< "
print items[m ":estimated_info"] "</td></tr>"
print "*/"
}
if (items[m ":estimated_settings"]){
print "postestimate_settings_" model_no "x_, /**< "
print items[m ":estimated_settings"] "</td></tr>"
print "*/"
}
}
else if (items[m ":" part]) print part "_x" model_no "x_, /**< " items[m ":" part] "*/"
else print m, part >> "missing_model_parts" #not at the moment important.
}
print "};"
}
}
|