GnmFunc: make this a GObject.
[gnumeric.git] / src / tools / analysis-signed-rank-test.c
blob48ed5c3e17c13555d5911018238216aed7ca7f62
1 /*
2 * analysis-signed-rank-test.c:
4 * Author:
5 * Andreas J. Guelzow <aguelzow@pyrshep.ca>
7 * (C) Copyright 2010, 2016 by Andreas J. Guelzow <aguelzow@pyrshep.ca>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <https://www.gnu.org/licenses/>.
24 #include <gnumeric-config.h>
25 #include <glib/gi18n-lib.h>
26 #include <gnumeric.h>
27 #include <tools/analysis-signed-rank-test.h>
28 #include <tools/analysis-tools.h>
29 #include <value.h>
30 #include <ranges.h>
31 #include <expr.h>
32 #include <func.h>
33 #include <numbers.h>
35 static inline GnmExpr const *
36 make_int (int n)
38 return gnm_expr_new_constant (value_new_int (n));
40 static inline GnmExpr const *
41 make_float (gnm_float x)
43 return gnm_expr_new_constant (value_new_float (x));
48 static gboolean
49 analysis_tool_signed_rank_test_engine_run (data_analysis_output_t *dao,
50 analysis_tools_data_sign_test_t *info)
52 guint col;
53 GSList *data = info->base.input;
54 gboolean first = TRUE;
56 GnmExpr const *expr;
57 GnmExpr const *expr_isnumber;
58 GnmExpr const *expr_diff;
59 GnmExpr const *expr_expect;
60 GnmExpr const *expr_var;
61 GnmExpr const *expr_abs;
62 GnmExpr const *expr_big;
64 GnmFunc *fd_median = analysis_tool_get_function ("MEDIAN", dao);
65 GnmFunc *fd_if = analysis_tool_get_function ("IF", dao);
66 GnmFunc *fd_sum = analysis_tool_get_function ("SUM", dao);
67 GnmFunc *fd_min = analysis_tool_get_function ("MIN", dao);
68 GnmFunc *fd_normdist = analysis_tool_get_function ("NORMDIST", dao);
69 GnmFunc *fd_isnumber = analysis_tool_get_function ("ISNUMBER", dao);
70 GnmFunc *fd_iferror = analysis_tool_get_function ("IFERROR", dao);
71 GnmFunc *fd_rank = analysis_tool_get_function ("RANK.AVG", dao);
72 GnmFunc *fd_abs = analysis_tool_get_function ("ABS", dao);
73 GnmFunc *fd_sqrt = analysis_tool_get_function ("SQRT", dao);
74 GnmFunc *fd_max = analysis_tool_get_function ("MAX", dao);
76 dao_set_italic (dao, 0, 0, 0, 9);
77 set_cell_text_col (dao, 0, 0, _("/Wilcoxon Signed Rank Test"
78 "/Median"
79 "/Predicted Median"
80 "/N"
81 "/S\xe2\x88\x92"
82 "/S+"
83 "/Test Statistic"
84 "/\xce\xb1"
85 "/P(T\xe2\x89\xa4t) one-tailed"
86 "/P(T\xe2\x89\xa4t) two-tailed"));
88 for (col = 0; data != NULL; data = data->next, col++) {
89 GnmValue *val_org = value_dup (data->data);
90 GnmExpr const *expr_org;
92 /* Note that analysis_tools_write_label may modify val_org */
93 dao_set_italic (dao, col + 1, 0, col+1, 0);
94 analysis_tools_write_label (val_org, dao, &info->base, col + 1, 0, col + 1);
95 expr_org = gnm_expr_new_constant (val_org);
97 if (first) {
98 dao_set_cell_float (dao, col + 1, 2, info->median);
99 dao_set_cell_float (dao, col + 1, 7, info->alpha);
100 first = FALSE;
101 } else {
102 dao_set_cell_expr (dao, col + 1, 2, make_cellref (-1,0));
103 dao_set_cell_expr (dao, col + 1, 7, make_cellref (-1,0));
106 expr_isnumber = gnm_expr_new_funcall3
107 (fd_if, gnm_expr_new_funcall1
108 (fd_isnumber, gnm_expr_copy (expr_org)),
109 make_int (1),
110 make_int (0));
112 expr = gnm_expr_new_funcall1
113 (fd_median,
114 gnm_expr_copy (expr_org));
115 dao_set_cell_expr (dao, col + 1, 1, expr);
117 expr_diff = gnm_expr_new_binary
118 (gnm_expr_copy (expr_org), GNM_EXPR_OP_SUB, make_cellref (0,-2));
119 expr_abs = gnm_expr_new_funcall1
120 (fd_abs, gnm_expr_copy (expr_diff));
121 expr_big = gnm_expr_new_binary
122 (gnm_expr_new_funcall1
123 (fd_max, gnm_expr_copy (expr_abs)),
124 GNM_EXPR_OP_ADD,
125 make_int (1));
126 expr = gnm_expr_new_funcall3
127 (fd_if,
128 gnm_expr_new_funcall1
129 (fd_isnumber, gnm_expr_copy (expr_org)),
130 gnm_expr_new_funcall3
131 (fd_if,
132 gnm_expr_new_binary
133 (gnm_expr_copy (expr_org),
134 GNM_EXPR_OP_EQUAL,
135 make_cellref (0,-2)),
136 gnm_expr_copy (expr_big),
137 expr_abs),
138 expr_big);
139 expr = gnm_expr_new_funcall3
140 (fd_rank,
141 gnm_expr_new_unary (GNM_EXPR_OP_UNARY_NEG,
142 expr_diff),
143 expr,
144 make_int (1));
146 dao_set_cell_array_expr
147 (dao, col + 1, 4,
148 gnm_expr_new_funcall1
149 (fd_sum,
150 gnm_expr_new_binary
151 (gnm_expr_copy (expr_isnumber),
152 GNM_EXPR_OP_MULT,
153 gnm_expr_new_funcall3
154 (fd_if,
155 gnm_expr_new_binary
156 (gnm_expr_copy (expr_org),
157 GNM_EXPR_OP_LT,
158 make_cellref (0,-2)),
159 expr,
160 make_int (0)))));
162 expr = gnm_expr_new_funcall1
163 (fd_sum, gnm_expr_new_binary
164 (expr_isnumber, GNM_EXPR_OP_MULT,
165 gnm_expr_new_funcall2
166 (fd_iferror, gnm_expr_new_funcall3
167 (fd_if, gnm_expr_new_binary (expr_org,
168 GNM_EXPR_OP_NOT_EQUAL, make_cellref (0,-1)),
169 make_int (1),
170 make_int (0)),
171 make_int (0))));
172 dao_set_cell_array_expr (dao, col + 1, 3, expr);
174 dao_set_cell_expr (dao, col + 1, 5,
175 gnm_expr_new_binary
176 (gnm_expr_new_binary
177 (gnm_expr_new_binary
178 (make_cellref (0,-2),
179 GNM_EXPR_OP_MULT,
180 gnm_expr_new_binary
181 (make_cellref (0,-2),
182 GNM_EXPR_OP_ADD,
183 make_int (1))),
184 GNM_EXPR_OP_DIV,
185 make_int (2)),
186 GNM_EXPR_OP_SUB,
187 make_cellref (0,-1)));
188 dao_set_cell_expr (dao, col + 1, 6,
189 gnm_expr_new_funcall2
190 (fd_min, make_cellref (0,-1), make_cellref (0,-2)));
192 expr_expect = gnm_expr_new_binary
193 (gnm_expr_new_binary
194 (make_cellref (0,-5),
195 GNM_EXPR_OP_MULT,
196 gnm_expr_new_binary
197 (make_cellref (0,-5),
198 GNM_EXPR_OP_ADD,
199 make_int (1))),
200 GNM_EXPR_OP_DIV,
201 make_int (4));
202 expr_var = gnm_expr_new_binary
203 (gnm_expr_new_binary
204 (gnm_expr_copy (expr_expect),
205 GNM_EXPR_OP_MULT,
206 gnm_expr_new_binary
207 (gnm_expr_new_binary
208 (make_int (2),
209 GNM_EXPR_OP_MULT,
210 make_cellref (0,-5)),
211 GNM_EXPR_OP_ADD,
212 make_int (1))),
213 GNM_EXPR_OP_DIV,
214 make_int (6));
215 expr = gnm_expr_new_funcall4
216 (fd_normdist, gnm_expr_new_binary
217 (make_cellref (0,-2),
218 GNM_EXPR_OP_ADD,
219 make_float (0.5)),
220 expr_expect,
221 gnm_expr_new_funcall1 (fd_sqrt, expr_var),
222 gnm_expr_new_constant (value_new_bool (TRUE)));
223 dao_set_cell_expr (dao, col + 1, 8,
224 gnm_expr_new_funcall3
225 (fd_if,
226 gnm_expr_new_binary
227 (make_cellref (0,-5),
228 GNM_EXPR_OP_LT,
229 make_int (12)),
230 gnm_expr_new_constant (value_new_error_NA (NULL)),
231 expr));
232 dao_set_cell_comment (dao, col + 1, 8,
233 _("This p-value is calculated by a normal approximation.\n"
234 "It is only valid if the sample size is at least 12."));
236 expr = gnm_expr_new_binary (make_int (2),
237 GNM_EXPR_OP_MULT, make_cellref (0,-1));
238 dao_set_cell_expr (dao, col + 1, 9, expr);
241 gnm_func_dec_usage (fd_median);
242 gnm_func_dec_usage (fd_if);
243 gnm_func_dec_usage (fd_min);
244 gnm_func_dec_usage (fd_sum);
245 gnm_func_dec_usage (fd_normdist);
246 gnm_func_dec_usage (fd_isnumber);
247 gnm_func_dec_usage (fd_iferror);
248 gnm_func_dec_usage (fd_rank);
249 gnm_func_dec_usage (fd_abs);
250 gnm_func_dec_usage (fd_sqrt);
251 gnm_func_dec_usage (fd_max);
253 dao_redraw_respan (dao);
255 return FALSE;
258 static gboolean
259 analysis_tool_signed_rank_test_two_engine_run (data_analysis_output_t *dao,
260 analysis_tools_data_sign_test_two_t *info)
262 GnmValue *val_1;
263 GnmValue *val_2;
265 GnmExpr const *expr_1;
266 GnmExpr const *expr_2;
268 GnmExpr const *expr;
269 GnmExpr const *expr_diff;
270 GnmExpr const *expr_diff_pred;
271 GnmExpr const *expr_isnumber_1;
272 GnmExpr const *expr_isnumber_2;
273 GnmExpr const *expr_isnumber;
274 GnmExpr const *expr_expect;
275 GnmExpr const *expr_var;
276 GnmExpr const *expr_abs;
277 GnmExpr const *expr_big;
279 GnmFunc *fd_median = analysis_tool_get_function ("MEDIAN", dao);
280 GnmFunc *fd_if = analysis_tool_get_function ("IF", dao);
281 GnmFunc *fd_sum = analysis_tool_get_function ("SUM", dao);
282 GnmFunc *fd_min = analysis_tool_get_function ("MIN", dao);
283 GnmFunc *fd_normdist = analysis_tool_get_function ("NORMDIST", dao);
284 GnmFunc *fd_isnumber = analysis_tool_get_function ("ISNUMBER", dao);
285 GnmFunc *fd_iferror = analysis_tool_get_function ("IFERROR", dao);
286 GnmFunc *fd_rank = analysis_tool_get_function ("RANK.AVG", dao);
287 GnmFunc *fd_abs = analysis_tool_get_function ("ABS", dao);
288 GnmFunc *fd_sqrt = analysis_tool_get_function ("SQRT", dao);
289 GnmFunc *fd_max = analysis_tool_get_function ("MAX", dao);
291 dao_set_italic (dao, 0, 0, 0, 10);
292 set_cell_text_col (dao, 0, 0, _("/Wilcoxon Signed Rank Test"
293 "/Median"
294 "/Observed Median Difference"
295 "/Predicted Median Difference"
296 "/N"
297 "/S\xe2\x88\x92"
298 "/S+"
299 "/Test Statistic"
300 "/\xce\xb1"
301 "/P(T\xe2\x89\xa4t) one-tailed"
302 "/P(T\xe2\x89\xa4t) two-tailed"));
303 val_1 = value_dup (info->base.range_1);
304 val_2 = value_dup (info->base.range_2);
306 /* Labels */
307 dao_set_italic (dao, 1, 0, 2, 0);
308 analysis_tools_write_label_ftest (val_1, dao, 1, 0,
309 info->base.labels, 1);
310 analysis_tools_write_label_ftest (val_2, dao, 2, 0,
311 info->base.labels, 2);
313 expr_1 = gnm_expr_new_constant (value_dup (val_1));
314 expr_2 = gnm_expr_new_constant (value_dup (val_2));
316 dao_set_cell_float (dao, 1, 3, info->median);
317 dao_set_cell_float (dao, 1, 8, info->base.alpha);
319 expr_isnumber_1 = gnm_expr_new_funcall3
320 (fd_if, gnm_expr_new_funcall1
321 (fd_isnumber, gnm_expr_copy (expr_1)),
322 make_int (1),
323 make_int (0));
324 expr_isnumber_2 = gnm_expr_new_funcall3
325 (fd_if, gnm_expr_new_funcall1
326 (fd_isnumber, gnm_expr_copy (expr_2)),
327 make_int (1),
328 make_int (0));
329 expr_isnumber = gnm_expr_new_binary
330 (expr_isnumber_1,
331 GNM_EXPR_OP_MULT,
332 expr_isnumber_2);
334 expr = gnm_expr_new_funcall1
335 (fd_median,
336 gnm_expr_new_funcall3
337 (fd_if,
338 gnm_expr_new_binary
339 (gnm_expr_copy (expr_isnumber),
340 GNM_EXPR_OP_EQUAL,
341 make_int (1)),
342 gnm_expr_copy (expr_1),
343 gnm_expr_new_constant (value_new_string(""))));
344 dao_set_cell_array_expr (dao, 1, 1, expr);
346 expr = gnm_expr_new_funcall1
347 (fd_median,
348 gnm_expr_new_funcall3
349 (fd_if,
350 gnm_expr_new_binary
351 (gnm_expr_copy (expr_isnumber),
352 GNM_EXPR_OP_EQUAL,
353 make_int (1)),
354 gnm_expr_copy (expr_2),
355 gnm_expr_new_constant (value_new_string(""))));
356 dao_set_cell_array_expr (dao, 2, 1, expr);
358 expr_diff = gnm_expr_new_binary (gnm_expr_copy (expr_1),
359 GNM_EXPR_OP_SUB,
360 gnm_expr_copy (expr_2));
361 dao_set_cell_array_expr
362 (dao, 1, 2,
363 gnm_expr_new_funcall1
364 (fd_median,
365 gnm_expr_new_funcall3
366 (fd_if,
367 gnm_expr_new_binary
368 (gnm_expr_copy (expr_isnumber),
369 GNM_EXPR_OP_EQUAL,
370 make_int (1)),
371 gnm_expr_copy (expr_diff),
372 gnm_expr_new_constant (value_new_string("")))));
374 expr = gnm_expr_new_funcall1
375 (fd_sum, gnm_expr_new_binary
376 (gnm_expr_copy (expr_isnumber),
377 GNM_EXPR_OP_MULT,
378 gnm_expr_new_funcall2
379 (fd_iferror, gnm_expr_new_funcall3
380 (fd_if, gnm_expr_new_binary
381 (gnm_expr_copy (expr_diff),
382 GNM_EXPR_OP_NOT_EQUAL, make_cellref (0,-1)),
383 make_int (1),
384 make_int (0)),
385 make_int (0))));
386 dao_set_cell_array_expr (dao, 1, 4, expr);
388 expr_diff_pred = gnm_expr_new_binary
389 (gnm_expr_copy (expr_diff),
390 GNM_EXPR_OP_SUB,
391 make_cellref (0,-2));
392 expr_abs = gnm_expr_new_funcall1
393 (fd_abs, gnm_expr_copy (expr_diff_pred));
394 expr_big = gnm_expr_new_binary
395 (gnm_expr_new_funcall1
396 (fd_max, gnm_expr_copy (expr_abs)),
397 GNM_EXPR_OP_ADD,
398 make_int (1));
399 expr = gnm_expr_new_funcall3
400 (fd_if,
401 gnm_expr_new_funcall1
402 (fd_isnumber, expr_1),
403 gnm_expr_new_funcall3
404 (fd_if,
405 gnm_expr_new_funcall1
406 (fd_isnumber, expr_2),
407 gnm_expr_new_funcall3
408 (fd_if,
409 gnm_expr_new_binary
410 (gnm_expr_copy (expr_diff),
411 GNM_EXPR_OP_EQUAL,
412 make_cellref (0,-2)),
413 gnm_expr_copy (expr_big),
414 expr_abs),
415 gnm_expr_copy (expr_big)),
416 expr_big);
417 expr = gnm_expr_new_funcall3
418 (fd_rank,
419 gnm_expr_new_unary (GNM_EXPR_OP_UNARY_NEG,
420 expr_diff_pred),
421 expr,
422 make_int (1));
423 expr = gnm_expr_new_funcall1
424 (fd_sum,
425 gnm_expr_new_binary
426 (expr_isnumber,
427 GNM_EXPR_OP_MULT,
428 gnm_expr_new_funcall3
429 (fd_if,
430 gnm_expr_new_binary
431 (expr_diff,
432 GNM_EXPR_OP_LT,
433 make_cellref (0,-2)),
434 expr,
435 make_int (0))));
437 dao_set_cell_array_expr (dao, 1, 5, expr);
439 dao_set_cell_expr (dao, 1, 6,
440 gnm_expr_new_binary
441 (gnm_expr_new_binary
442 (gnm_expr_new_binary
443 (make_cellref (0,-2),
444 GNM_EXPR_OP_MULT,
445 gnm_expr_new_binary
446 (make_cellref (0,-2),
447 GNM_EXPR_OP_ADD,
448 make_int (1))),
449 GNM_EXPR_OP_DIV,
450 make_int (2)),
451 GNM_EXPR_OP_SUB,
452 make_cellref (0,-1)));
454 dao_set_cell_expr
455 (dao, 1, 7,
456 gnm_expr_new_funcall2
457 (fd_min, make_cellref (0,-1), make_cellref (0,-2)));
459 expr_expect = gnm_expr_new_binary
460 (gnm_expr_new_binary
461 (make_cellref (0,-5),
462 GNM_EXPR_OP_MULT,
463 gnm_expr_new_binary
464 (make_cellref (0,-5),
465 GNM_EXPR_OP_ADD,
466 make_int (1))),
467 GNM_EXPR_OP_DIV,
468 make_int (4));
469 expr_var = gnm_expr_new_binary
470 (gnm_expr_new_binary
471 (gnm_expr_copy (expr_expect),
472 GNM_EXPR_OP_MULT,
473 gnm_expr_new_binary
474 (gnm_expr_new_binary
475 (make_int (2),
476 GNM_EXPR_OP_MULT,
477 make_cellref (0,-5)),
478 GNM_EXPR_OP_ADD,
479 make_int (1))),
480 GNM_EXPR_OP_DIV,
481 make_int (6));
482 expr = gnm_expr_new_funcall4
483 (fd_normdist, gnm_expr_new_binary
484 (make_cellref (0,-2),
485 GNM_EXPR_OP_ADD,
486 make_float (0.5)),
487 expr_expect,
488 gnm_expr_new_funcall1 (fd_sqrt, expr_var),
489 gnm_expr_new_constant (value_new_bool (TRUE)));
490 dao_set_cell_expr (dao, 1, 9,
491 gnm_expr_new_funcall3
492 (fd_if,
493 gnm_expr_new_binary
494 (make_cellref (0,-5),
495 GNM_EXPR_OP_LT,
496 make_int (12)),
497 gnm_expr_new_constant (value_new_error_NA (NULL)),
498 expr));
499 dao_set_cell_comment
500 (dao, 1, 9,
501 _("This p-value is calculated by a normal approximation.\n"
502 "It is only valid if the sample size is at least 12."));
504 expr = gnm_expr_new_binary (make_int (2),
505 GNM_EXPR_OP_MULT, make_cellref (0,-1));
506 dao_set_cell_array_expr (dao, 1, 10, expr);
508 gnm_func_dec_usage (fd_median);
509 gnm_func_dec_usage (fd_if);
510 gnm_func_dec_usage (fd_min);
511 gnm_func_dec_usage (fd_sum);
512 gnm_func_dec_usage (fd_normdist);
513 gnm_func_dec_usage (fd_isnumber);
514 gnm_func_dec_usage (fd_iferror);
515 gnm_func_dec_usage (fd_rank);
516 gnm_func_dec_usage (fd_abs);
517 gnm_func_dec_usage (fd_sqrt);
518 gnm_func_dec_usage (fd_max);
520 value_release (val_1);
521 value_release (val_2);
523 dao_redraw_respan (dao);
525 return FALSE;
528 gboolean
529 analysis_tool_signed_rank_test_engine (G_GNUC_UNUSED GOCmdContext *gcc, data_analysis_output_t *dao, gpointer specs,
530 analysis_tool_engine_t selector, gpointer result)
532 analysis_tools_data_sign_test_t *info = specs;
534 switch (selector) {
535 case TOOL_ENGINE_UPDATE_DESCRIPTOR:
536 return (dao_command_descriptor
537 (dao, _("Wilcoxon Signed Rank Test (%s)"), result)
538 == NULL);
539 case TOOL_ENGINE_UPDATE_DAO:
540 prepare_input_range (&info->base.input, info->base.group_by);
541 dao_adjust (dao, 1 + g_slist_length (info->base.input), 10);
542 return FALSE;
543 case TOOL_ENGINE_CLEAN_UP:
544 return analysis_tool_generic_clean (specs);
545 case TOOL_ENGINE_LAST_VALIDITY_CHECK:
546 return FALSE;
547 case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
548 dao_prepare_output (NULL, dao, _("Wilcoxon Signed Rank Test"));
549 return FALSE;
550 case TOOL_ENGINE_FORMAT_OUTPUT_RANGE:
551 return dao_format_output (dao, _("Wilcoxon Signed Rank Test"));
552 case TOOL_ENGINE_PERFORM_CALC:
553 default:
554 return analysis_tool_signed_rank_test_engine_run (dao, specs);
556 return TRUE;
559 gboolean
560 analysis_tool_signed_rank_test_two_engine (G_GNUC_UNUSED GOCmdContext *gcc, data_analysis_output_t *dao, gpointer specs,
561 analysis_tool_engine_t selector, gpointer result)
563 switch (selector) {
564 case TOOL_ENGINE_UPDATE_DESCRIPTOR:
565 return (dao_command_descriptor
566 (dao, _("Wilcoxon Signed Rank Test (%s)"), result)
567 == NULL);
568 case TOOL_ENGINE_UPDATE_DAO:
569 dao_adjust (dao, 3, 11);
570 return FALSE;
571 case TOOL_ENGINE_CLEAN_UP:
572 return analysis_tool_generic_b_clean (specs);
573 case TOOL_ENGINE_LAST_VALIDITY_CHECK:
574 return FALSE;
575 case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
576 dao_prepare_output (NULL, dao, _("Wilcoxon Signed Rank Test"));
577 return FALSE;
578 case TOOL_ENGINE_FORMAT_OUTPUT_RANGE:
579 return dao_format_output (dao, _("Wilcoxon Signed Rank Test"));
580 case TOOL_ENGINE_PERFORM_CALC:
581 default:
582 return analysis_tool_signed_rank_test_two_engine_run (dao, specs);
584 return TRUE; /* We shouldn't get here */