2 # -----------------------------------------------------------------------------
14 my $of = "of the distribution";
15 my @common = ('give_log' =>
16 "if true, log of the result will be returned instead",
19 "if true (the default), the lower tail of the distribution is considered",
21 'log_p' => 'if true, the natural logarithm of the probability is given or returned; defaults to false',
24 'p' => 'probability or natural logarithm of the probability',
26 'shape' => "the shape parameter $of",
27 'scale' => "the scale parameter $of",
30 $funcs{'dnorm'} = $funcs{'pnorm'} = $funcs{'qnorm'} =
33 ({ 'mu' => "mean $of",
34 'sigma' => "standard deviation $of",
36 [ { 'x' => 1, 'mu' => 0, 'sigma' => 1 },
37 { 'x' => 2, 'mu' => 0, 'sigma' => 1 },
38 { 'x' => 3, 'mu' => 0, 'sigma' => 1 } ],
41 $funcs{'dlnorm'} = $funcs{'plnorm'} = $funcs{'qlnorm'} =
44 ({ 'logmean' => "mean of the underlying normal distribution",
45 'logsd' => "standard deviation of the underlying normal distribution",
47 [ { 'x' => 2.5, 'logmean' => 1, 'logsd' => 2 } ],
50 $funcs{'dgamma'} = $funcs{'pgamma'} = $funcs{'qgamma'} =
54 [ { 'x' => 3, 'shape' => 5, 'scale' => 1 } ],
57 $funcs{'dbeta'} = $funcs{'pbeta'} = $funcs{'qbeta'} =
60 ({ 'a' => "the first shape parameter $of",
61 'b' => "the second scale parameter $of",
63 [ { 'x' => 0.4, 'a' => 1, 'b' => 4 } ],
66 $funcs{'dt'} = $funcs{'pt'} = $funcs{'qt'} =
69 ({ 'n' => "the number of degrees of freedom $of",
71 [ { 'x' => 1.5, 'n' => 5 } ],
74 $funcs{'df'} = $funcs{'pf'} = $funcs{'qf'} =
77 ({ 'n1' => "the first number of degrees of freedom $of",
78 'n2' => "the second number of degrees of freedom $of",
80 [ { 'x' => 1.5, 'n1' => 2, 'n2' => 3 } ],
83 $funcs{'dchisq'} = $funcs{'pchisq'} = $funcs{'qchisq'} =
86 ({ 'df' => "the number of degrees of freedom $of",
88 [ { 'x' => 2.5, 'df' => 4 } ],
91 $funcs{'dweibull'} = $funcs{'pweibull'} = $funcs{'qweibull'} =
95 [ { 'x' => 2.1, 'shape' => 1.5, 'scale' => 1 } ],
98 $funcs{'dpois'} = $funcs{'ppois'} = $funcs{'qpois'} =
101 ({ 'lambda' => "the mean $of",
103 [ { 'x' => 4, 'lambda' => 4 } ],
106 $funcs{'dexp'} = $funcs{'pexp'} = $funcs{'qexp'} =
110 [ { 'x' => 1.5, 'scale' => 4 } ],
113 $funcs{'dbinom'} = $funcs{'pbinom'} = $funcs{'qbinom'} =
116 ({ 'n' => 'the number of trials',
117 'psuc' => "the probability of success in each trial",
119 [ { 'x' => 4, 'n' => 10, 'psuc' => 0.4 } ],
122 $funcs{'dnbinom'} = $funcs{'pnbinom'} = $funcs{'qnbinom'} =
125 ({ 'n' => 'required number of successes',
126 'psuc' => "the probability of success in each trial",
128 'x' => 'observation (number of failures)' }),
129 [ { 'x' => 8, 'n' => 10, 'psuc' => 0.45 } ],
132 $funcs{'dhyper'} = $funcs{'phyper'} = $funcs{'qhyper'} =
135 ({ 'r' => "the number of red balls",
136 'b' => "the number of black balls",
137 'n' => "the number of balls drawn",
139 [ { 'x' => 12, 'r' => 50, 'b' => 450, 'n' => 100 } ],
142 $funcs{'dcauchy'} = $funcs{'pcauchy'} = $funcs{'qcauchy'} =
145 ({ 'location' => "the center $of",
147 [ { 'x' => 1.5, 'location' => 1, 'scale' => 4 } ],
150 $funcs{'dgeom'} = $funcs{'pgeom'} = $funcs{'qgeom'} =
153 ({ 'psuc' => "the probability of success in each trial",
155 [ { 'x' => 3, 'psuc' => 0.2 } ],
158 $funcs{'dsnorm'} = $funcs{'psnorm'} = $funcs{'qsnorm'} =
161 ({ 'location' => "the location parameter $of",
163 [ { 'x' => 3, 'shape' => 2, 'location' => 0, 'scale' => 1 } ],
166 $funcs{'dst'} = $funcs{'pst'} = $funcs{'qst'} =
169 ({ 'n' => "the number of degrees of freedom $of",
171 [ { 'x' => 2, 'n' => 5, 'shape' => 2 } ],
174 $funcs{'ptukey'} = $funcs{'qtukey'} =
177 ({ 'nranges' => "the number of ranges; default is 1",
178 'nmeans' => "the number of means",
179 'df' => "the number of degrees of freedom $of",
182 $defaults{'ptukey:nranges'} = $defaults{'qtukey:nranges'} = 1;
184 $funcs{'dgumbel'} = $funcs{'pgumbel'} = $funcs{'qgumbel'} =
187 ({ 'mu' => "the location parameter of freedom $of",
188 'beta' => "the scale parameter of freedom $of",
190 [ { 'x' => 2.5, 'mu' => 2, 'beta' => 1 } ],
193 $funcs{'drayleigh'} = $funcs{'prayleigh'} = $funcs{'qrayleigh'} =
197 [ { 'x' => 2, 'scale' => 1 } ],
203 ('qchisq' => 'A two argument invocation R.QCHISQ(@{p},@{df}) is exported to OpenFormula as CHISQINV(@{p},@{df}).',
204 'pchisq' => 'A two argument invocation R.PCHISQ(@{x},@{df}) is exported to OpenFormula as CHISQDIST(@{x},@{df}).',
205 'dchisq' => 'A two argument invocation R.DCHISQ(@{x},@{df}) is exported to OpenFormula as CHISQDIST(@{x},@{df},FALSE()).',
208 my %test_status = ();
210 ('pbeta', 'pbinom', 'pcauchy', 'pchisq', 'pexp',
211 'pf', 'pgamma', 'pgeom', 'phyper', 'dhyper', 'plnorm',
212 'pnbinom', 'pnorm', 'ppois', 'pt', 'pweibull', );
214 ('dbeta', 'dbinom', 'dcauchy', 'dchisq', 'dexp', 'df', 'dgamma',
215 'dhyper', 'dlnorm', 'dnbinom', 'dnorm', 'dpois', 'dt',
216 'dweibull', 'pbeta', 'pbinom', 'pcauchy', 'pchisq', 'pexp', 'pf',
217 'pgamma', 'phyper', 'plnorm', 'pnbinom', 'pnorm', 'ppois', 'pt',
218 'pweibull', 'qbeta', 'qcauchy', 'qchisq', 'qexp', 'qf', 'qgamma',
219 'qlnorm', 'qnorm', 'qt', 'qweibull');
220 foreach (@burkardt_tests, @amath_tests) {
221 $test_status{$_} = 'EXHAUSTIVE';
225 ('gnm_float' => 'value_get_as_float',
226 'gboolean' => 'value_get_as_checked_bool',
235 ('gnm_float' => 'value_new_float',
236 'int' => 'value_new_int',
237 'gboolean' => 'value_new_bool',
240 # -----------------------------------------------------------------------------
243 $mathfunch =~ s
|[^/]+$|../../src/mathfunc
.h
|;
246 $dpqh =~ s
|[^/]+$|../../src/sf
-dpq
.h
|;
254 &emit
("/* This code was generated by $0. Do not edit. */\n\n" .
255 "#include <gnumeric-config.h>\n" .
256 "#include <gnumeric.h>\n" .
257 "#include <goffice/goffice.h>\n" .
258 "#include <gnm-plugin.h>\n" .
259 "#include <func.h>\n" .
260 "#include <gnm-i18n.h>\n" .
261 "#include <value.h>\n" .
262 "#include <mathfunc.h>\n" .
263 "#include <sf-dpq.h>\n" .
264 "#include \"extra.h\"\n\n" .
265 "GNM_PLUGIN_MODULE_HEADER;\n\n");
267 foreach my $header ($mathfunch, $dpqh, "extra.h") {
269 open (HEADER
, "<$header") or die "$0: Cannot read $header: $!\n";
273 if (/^(gnm_float)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(.*\)/) {
276 next unless exists $funcs{$func};
277 $functions{$func} = [$restype,$_];
283 foreach my $func (sort { &cfileorder
($a,$b) } keys %functions) {
284 my ($restype,$proto) = @
{$functions{$func}};
285 my ($handler,@args) = @
{ $funcs{$func} };
286 &$handler ($func, $restype, $proto, @args);
292 &emit
("G_MODULE_EXPORT void\n" .
293 "go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)\n" .
297 &emit
("G_MODULE_EXPORT void\n" .
298 "go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc)\n" .
304 &emit
("GnmFuncDescriptor const rstat_functions[] = {\n" .
308 &emit_dump
("functions.c");
310 &create_plugin_xml_in
(keys %functions);
312 # -----------------------------------------------------------------------------
316 return ((substr($a,1) cmp substr($b,1)) ||
317 (substr($a,0,1) cmp substr($b,0,1)));
320 # -----------------------------------------------------------------------------
323 my ($func,$restype,$proto,$distname,$argdescs,$psamples) = @_;
326 $args =~ s/^.*\((.*)\)\s*;$/$1/;
329 foreach (split (/\s*,\s*/, $args)) {
330 my ($type,$name) = split (' ');
331 $name = $argoverride{"$func:$name"} || $argoverride{$name} || $name;
332 push @args, [$type,$name];
335 # ----------------------------------------
336 # Output help description.
339 &emit
("static GnmFuncHelp const help_r_$func\[\] = {\n");
341 my $short_what = ($func =~ /^d/
342 ?
"probability density function"
344 ?
"cumulative distribution function"
345 : "probability quantile function")) .
346 " of the $distname distribution";
347 &emit
("\t{ GNM_FUNC_HELP_NAME, F_(\"" . uc ("r.$func") . ":$short_what\") },\n");
350 my ($type,$name) = @
{ $_ };
352 my $desc = $argdescs->{$name};
353 if (!defined $desc) {
355 warn "$0: Argument $name of r.$func has no description\n";
357 &emit
("\t{ GNM_FUNC_HELP_ARG, F_(\"$name:$desc\") },\n");
360 my $what = "This function returns the " .
362 ?
"probability density function"
364 ?
"cumulative distribution function"
365 : "probability quantile function, i.e., the inverse of the cumulative distribution function,")) .
366 " of the $distname distribution.";
367 &emit
("\t{ GNM_FUNC_HELP_DESCRIPTION, F_(\"$what\") },\n");
369 my $odf = $odf_note{$func};
371 &emit
("\t{ GNM_FUNC_HELP_ODF, F_(\"$odf\") },\n");
374 my $sdef = { 'p' => 0.3,
376 'lower_tail' => undef};
380 foreach my $s (@
$psamples) {
381 my @sample_args = ();
384 my ($type,$name) = @
{ $_ };
385 if (exists $s->{$name}) {
387 push @sample_args, $a;
388 } elsif (exists $sdef->{$name}) {
389 my $a = $sdef->{$name};
390 last ARG
unless defined $a;
391 push @sample_args, $a;
396 &emit
("\t{ GNM_FUNC_HELP_EXAMPLES, \"=r.$func(" . join (",", @sample_args) . ")\" },\n");
401 my $f1 = substr ($func, 1);
403 $seealso .= ",R.D$F1" if ($func !~ /^d/) && exists $funcs{"d$f1"};
404 $seealso .= ",R.P$F1" if $func !~ /^p/ && exists $funcs{"p$f1"};
405 $seealso .= ",R.Q$F1" if $func !~ /^q/ && exists $funcs{"q$f1"};
406 $seealso =~ s/^,\s*//;
408 &emit
("\t{ GNM_FUNC_HELP_SEEALSO, \"$seealso\" },\n");
411 &emit
("\t{ GNM_FUNC_HELP_END }\n" .
414 # ----------------------------------------
415 # Output the function body.
417 &emit
("static GnmValue *\n" .
418 "gnumeric_r_$func (GnmFuncEvalInfo *ei, GnmValue const * const *args)\n" .
424 my ($type,$name) = @
{ $_ };
425 my $def = $defaults{"$func:$name"};
426 $def = 'TRUE' if $name eq 'lower_tail';
427 $def = 'FALSE' if $name eq 'give_log' || $name eq 'log_p';
429 &emit
("\t$type $name = " .
430 (defined ($def) ?
"args[$n] ? " : "") .
431 $type_getter{$type} . " (args[$n])" .
432 (defined ($def) ?
" : $def" : "") .
435 if ($typespec =~ /\|/) {
436 die "$0: argument $name for $func needs a default"
438 } elsif (defined ($def)) {
441 $typespec .= $type_spec{$type};
446 "\treturn " . $type_setter{$restype} . " (" .
447 "$func (" . join (", ", map { $_->[1] } @args) . "));\n" .
450 my $arglist = join (",", map { $_->[1] } @args);
452 my $test_status = $test_status{$func} || 'NO_TESTSUITE';
454 $funcdefs .= ("\t{\n" .
455 "\t\t\"r.$func\",\n" .
456 "\t\t\"$typespec\",\n" .
457 "\t\thelp_r_$func,\n" .
458 "\t\tgnumeric_r_$func, NULL,\n" .
459 "\t\tGNM_FUNC_SIMPLE, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_$test_status,\n" .
463 # -----------------------------------------------------------------------------
471 &emit
("/* " . ('-' x
73) . " */\n\n");
477 my $tmpfilename = "$filename.new";
478 print STDERR
"Creating $filename";
480 open (FIL
, ">$tmpfilename") or die "Cannot write to $tmpfilename: $!\n";
484 &update_file
($filename);
489 # -----------------------------------------------------------------------------
493 my ($new) = "$old.new";
497 die "$0: Cannot rename $new to $old: $!\n";
498 print STDERR
" -- done.\n";
500 system ("cmp '$old' '$new' >/dev/null");
502 print STDERR
" -- unchanged.\n";
506 die "$0: Cannot rename $new to $old: $!\n";
507 print STDERR
" -- done.\n";
512 # -----------------------------------------------------------------------------
514 sub create_plugin_xml_in
{
515 my (@funcnames) = @_;
517 &emit
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
518 "<plugin id=\"Gnumeric_r\">\n" .
519 "\t<information>\n" .
520 "\t\t<_name>Statistical Functions</_name>\n" .
521 "\t\t<_description>Statistical Functions with naming and calling conventions from The R Project</_description>\n" .
522 "\t</information>\n" .
523 "\t<loader type=\"Gnumeric_Builtin:module\">\n" .
524 "\t\t<attribute name=\"module_file\" value=\"rstat\"/>\n" .
527 "\t\t<service type=\"function_group\" id=\"rstat\">\n" .
528 "\t\t\t<_category>Statistics</_category>\n" .
529 "\t\t\t<functions textdomain=\"gnumeric-VERSION-functions\">\n");
531 foreach my $func (sort @funcnames) {
532 my $rfunc = "r.$func";
533 &emit
("\t\t\t\t<function name=\"$rfunc\"/>\n");
536 &emit
("\t\t\t</functions>\n" .
541 &emit_dump
("plugin.xml.in");
544 # -----------------------------------------------------------------------------