1 /*
2  * analysis-exp-smoothing.c:
3  *
4   * This is a complete reimplementation of the exponential smoothing tool in tool in 2008
5  *
6  * Author:
7  *   Andreas J. Guelzow  <aguelzow@pyrshep.ca>
8  *
9  * (C) Copyright 2008 by Andreas J. Guelzow  <aguelzow@pyrshep.ca>
10  *
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, see <https://www.gnu.org/licenses/>.
24  */
25 
26 #include <gnumeric-config.h>
27 #include <glib/gi18n-lib.h>
28 #include <gnumeric.h>
29 #include <tools/analysis-exp-smoothing.h>
30 #include <tools/analysis-tools.h>
31 #include <value.h>
32 #include <ranges.h>
33 #include <expr.h>
34 #include <graph.h>
35 #include <func.h>
36 #include <numbers.h>
37 #include <sheet-object-graph.h>
38 #include <goffice/goffice.h>
39 #include <sheet.h>
40 
41 
42 static GnmExpr const *
analysis_tool_exp_smoothing_funcall5(GnmFunc * fd,GnmExpr const * ex,int y,int x,int dy,int dx)43 analysis_tool_exp_smoothing_funcall5 (GnmFunc *fd, GnmExpr const *ex, int y, int x, int dy, int dx)
44 {
45 	GnmExprList *list;
46 	list = gnm_expr_list_prepend (NULL, gnm_expr_new_constant (value_new_int (dx)));
47 	list = gnm_expr_list_prepend (list, gnm_expr_new_constant (value_new_int (dy)));
48 	list = gnm_expr_list_prepend (list, gnm_expr_new_constant (value_new_int (x)));
49 	list = gnm_expr_list_prepend (list, gnm_expr_new_constant (value_new_int (y)));
50 	list = gnm_expr_list_prepend (list, ex);
51 
52 	return gnm_expr_new_funcall (fd, list);
53 }
54 
55 static void
create_line_plot(GogPlot ** plot,SheetObject ** so)56 create_line_plot (GogPlot **plot, SheetObject **so)
57 {
58 		GogGraph     *graph;
59 		GogChart     *chart;
60 
61 		graph = g_object_new (GOG_TYPE_GRAPH, NULL);
62 		chart = GOG_CHART (gog_object_add_by_name (GOG_OBJECT (graph), "Chart", NULL));
63 		*plot = gog_plot_new_by_name ("GogLinePlot");
64 		gog_object_add_by_name (GOG_OBJECT (chart), "Plot", GOG_OBJECT (*plot));
65 		*so = sheet_object_graph_new (graph);
66 		g_object_unref (graph);
67 }
68 
69 static void
attach_series(GogPlot * plot,GOData * expr)70 attach_series (GogPlot *plot, GOData *expr)
71 {
72 	GogSeries    *series;
73 
74 	g_return_if_fail (plot != NULL);
75 
76 	series = gog_plot_new_series (plot);
77 	gog_series_set_dim (series, 1, expr, NULL);
78 }
79 
80 static gboolean
analysis_tool_exponential_smoothing_engine_ses_h_run(data_analysis_output_t * dao,analysis_tools_data_exponential_smoothing_t * info)81 analysis_tool_exponential_smoothing_engine_ses_h_run (data_analysis_output_t *dao,
82 						analysis_tools_data_exponential_smoothing_t *info)
83 {
84 	GSList *l;
85 	gint col = 0;
86 	gint source;
87 	SheetObject *so = NULL;
88 	GogPlot	     *plot = NULL;
89 	GnmFunc *fd_index;
90 	GnmFunc *fd_offset;
91 	GnmFunc *fd_sqrt = NULL;
92 	GnmFunc *fd_sumxmy2 = NULL;
93 	GnmExpr const *expr_alpha = NULL;
94 
95 	if (info->std_error_flag) {
96 		fd_sqrt = gnm_func_lookup_or_add_placeholder ("SQRT");
97 		gnm_func_inc_usage (fd_sqrt);
98 		fd_sumxmy2 = gnm_func_lookup_or_add_placeholder ("SUMXMY2");
99 		gnm_func_inc_usage (fd_sumxmy2);
100 	}
101 
102 	fd_index = gnm_func_lookup_or_add_placeholder ("INDEX");
103 	gnm_func_inc_usage (fd_index);
104 	fd_offset = gnm_func_lookup_or_add_placeholder ("OFFSET");
105 	gnm_func_inc_usage (fd_offset);
106 
107 	if (info->show_graph)
108 		create_line_plot (&plot, &so);
109 
110 	dao_set_italic (dao, 0, 0, 0, 0);
111 	dao_set_cell (dao, 0, 0, _("Exponential Smoothing"));
112 	dao_set_format  (dao, 0, 1, 0, 1, _("\"\xce\xb1 =\" * 0.000"));
113 	dao_set_cell_expr (dao, 0, 1, gnm_expr_new_constant (value_new_float (info->damp_fact)));
114 	expr_alpha = dao_get_cellref (dao, 0, 1);
115 
116 	dao->offset_row = 2;
117 
118 	for (l = info->base.input, source = 1; l; l = l->next, col++, source++) {
119 		GnmValue *val = value_dup ((GnmValue *)l->data);
120 		GnmValue *val_c = NULL;
121 		GnmExpr const *expr_title = NULL;
122 		GnmExpr const *expr_input = NULL;
123 		gint height;
124 		gint  x = 1;
125 		gint  y = 1;
126 		gint  *mover;
127 		guint delta_x = 1;
128 		guint delta_y = 1;
129 		gint row;
130 		Sheet *sheet;
131 		GnmEvalPos ep;
132 
133 		sheet = val->v_range.cell.a.sheet;
134 		eval_pos_init_sheet (&ep, sheet);
135 
136 		dao_set_italic (dao, col, 0, col, 0);
137 		if (info->base.labels) {
138 			val_c = value_dup (val);
139 			switch (info->base.group_by) {
140 			case GROUPED_BY_ROW:
141 				val->v_range.cell.a.col++;
142 				break;
143 			default:
144 				val->v_range.cell.a.row++;
145 				break;
146 			}
147 			expr_title = gnm_expr_new_funcall1 (fd_index,
148 							    gnm_expr_new_constant (val_c));
149 
150 			dao_set_cell_expr (dao, col, 0, expr_title);
151 		} else
152 			dao_set_cell_printf
153 				(dao, col, 0,
154 				 (info->base.group_by == GROUPED_BY_ROW ?
155 				  _("Row %d") : _("Column %d")),
156 				 source);
157 
158 		switch (info->base.group_by) {
159 		case GROUPED_BY_ROW:
160 			height = value_area_get_width (val, &ep);
161 			mover = &x;
162 			break;
163 		default:
164 			height = value_area_get_height (val, &ep);
165 			mover = &y;
166 			break;
167 		}
168 
169 		expr_input = gnm_expr_new_constant (val);
170 
171 		if (plot != NULL) {
172 			attach_series (plot, gnm_go_data_vector_new_expr (sheet, gnm_expr_top_new
173 									  (gnm_expr_copy (expr_input))));
174 			attach_series (plot, dao_go_data_vector (dao, col, 1, col, height));
175 		}
176 
177 		/*  F(t+1) = F(t) + damp_fact * ( A(t) - F(t) ) */
178 		(*mover) = 1;
179 		dao_set_cell_expr (dao, col, 1,
180 				   gnm_expr_new_funcall1 (fd_index,
181 							  gnm_expr_copy (expr_input)));
182 
183 		for (row = 2; row <= height; row++, (*mover)++) {
184 			GnmExpr const *A;
185 			GnmExpr const *F;
186 
187 			A = gnm_expr_new_binary (gnm_expr_copy (expr_alpha),
188 						 GNM_EXPR_OP_MULT,
189 						 gnm_expr_new_funcall3
190 						 (fd_index,
191 						  gnm_expr_copy (expr_input),
192 						  gnm_expr_new_constant(value_new_int(y)),
193 						  gnm_expr_new_constant(value_new_int(x))));
194 			F = gnm_expr_new_binary (gnm_expr_new_binary (gnm_expr_new_constant
195 								      (value_new_int (1)),
196 								      GNM_EXPR_OP_SUB,
197 								      gnm_expr_copy (expr_alpha)),
198 						 GNM_EXPR_OP_MULT,
199 						 make_cellref (0, -1));
200 			dao_set_cell_expr (dao, col, row, gnm_expr_new_binary (A, GNM_EXPR_OP_ADD, F));
201 		}
202 
203 		if (info->std_error_flag) {
204 			col++;
205 			dao_set_italic (dao, col, 0, col, 0);
206 			dao_set_cell (dao, col, 0, _("Standard Error"));
207 
208 			y = 0;
209 			x = 0;
210 			(*mover) = 1;
211 			for (row = 1; row <= height; row++) {
212 				if (row > 1 && row <= height && (row - 1 - info->df) > 0) {
213 					GnmExpr const *expr_offset;
214 
215 					if (info->base.group_by == GROUPED_BY_ROW)
216 						delta_x = row - 1;
217 					else
218 						delta_y = row - 1;
219 
220 					expr_offset = analysis_tool_exp_smoothing_funcall5
221 						(fd_offset, gnm_expr_copy (expr_input), y, x, delta_y, delta_x);
222 					dao_set_cell_expr (dao, col, row,
223 							   gnm_expr_new_funcall1
224 							   (fd_sqrt,
225 							    gnm_expr_new_binary
226 							    (gnm_expr_new_funcall2
227 							     (fd_sumxmy2,
228 							      expr_offset,
229 							      make_rangeref (-1, 2 - row, -1, 0)),
230 							     GNM_EXPR_OP_DIV,
231 							     gnm_expr_new_constant (value_new_int
232 										    (row - 1 - info->df)))));
233 				} else
234 					dao_set_cell_na (dao, col, row);
235 			}
236 		}
237 
238 		gnm_expr_free (expr_input);
239 	}
240 
241 	if (so != NULL)
242 		dao_set_sheet_object (dao, 0, 1, so);
243 
244 	gnm_expr_free (expr_alpha);
245 	if (fd_sqrt != NULL)
246 		gnm_func_dec_usage (fd_sqrt);
247 	if (fd_sumxmy2 != NULL)
248 		gnm_func_dec_usage (fd_sumxmy2);
249 	gnm_func_dec_usage (fd_offset);
250 	gnm_func_dec_usage (fd_index);
251 
252 	dao_redraw_respan (dao);
253 
254 	return FALSE;
255 }
256 
257 static gboolean
analysis_tool_exponential_smoothing_engine_ses_r_run(data_analysis_output_t * dao,analysis_tools_data_exponential_smoothing_t * info)258 analysis_tool_exponential_smoothing_engine_ses_r_run (data_analysis_output_t *dao,
259 						analysis_tools_data_exponential_smoothing_t *info)
260 {
261 	GSList *l;
262 	gint col = 0;
263 	gint source;
264 	SheetObject *so = NULL;
265 	GogPlot	     *plot = NULL;
266 	GnmFunc *fd_index;
267 	GnmFunc *fd_offset;
268 	GnmFunc *fd_average;
269 	GnmFunc *fd_sqrt = NULL;
270 	GnmFunc *fd_sumxmy2 = NULL;
271 	GnmExpr const *expr_alpha = NULL;
272 
273 	if (info->std_error_flag) {
274 		fd_sqrt = gnm_func_lookup_or_add_placeholder ("SQRT");
275 		gnm_func_inc_usage (fd_sqrt);
276 		fd_sumxmy2 = gnm_func_lookup_or_add_placeholder ("SUMXMY2");
277 		gnm_func_inc_usage (fd_sumxmy2);
278 	}
279 	fd_average = gnm_func_lookup_or_add_placeholder ("AVERAGE");
280 	gnm_func_inc_usage (fd_average);
281 	fd_index = gnm_func_lookup_or_add_placeholder ("INDEX");
282 	gnm_func_inc_usage (fd_index);
283 	fd_offset = gnm_func_lookup_or_add_placeholder ("OFFSET");
284 	gnm_func_inc_usage (fd_offset);
285 
286 	if (info->show_graph)
287 		create_line_plot (&plot, &so);
288 
289 	dao_set_italic (dao, 0, 0, 0, 0);
290 	dao_set_cell (dao, 0, 0, _("Exponential Smoothing"));
291 	dao_set_format  (dao, 0, 1, 0, 1, _("\"\xce\xb1 =\" * 0.000"));
292 	dao_set_cell_expr (dao, 0, 1, gnm_expr_new_constant (value_new_float (info->damp_fact)));
293 	expr_alpha = dao_get_cellref (dao, 0, 1);
294 
295 	dao->offset_row = 2;
296 
297 	for (l = info->base.input, source = 1; l; l = l->next, col++, source++) {
298 		GnmValue *val = value_dup ((GnmValue *)l->data);
299 		GnmValue *val_c = NULL;
300 		GnmExpr const *expr_title = NULL;
301 		GnmExpr const *expr_input = NULL;
302 		gint height;
303 		gint  x = 1;
304 		gint  y = 1;
305 		gint  *mover;
306 		guint delta_x = 1;
307 		guint delta_y = 1;
308 		gint row;
309 		Sheet *sheet;
310 		GnmEvalPos ep;
311 
312 		sheet = val->v_range.cell.a.sheet;
313 		eval_pos_init_sheet (&ep, sheet);
314 
315 		dao_set_italic (dao, col, 0, col, 0);
316 		if (info->base.labels) {
317 			val_c = value_dup (val);
318 			switch (info->base.group_by) {
319 			case GROUPED_BY_ROW:
320 				val->v_range.cell.a.col++;
321 				break;
322 			default:
323 				val->v_range.cell.a.row++;
324 				break;
325 			}
326 			expr_title = gnm_expr_new_funcall1 (fd_index,
327 							    gnm_expr_new_constant (val_c));
328 
329 			dao_set_cell_expr (dao, col, 0, expr_title);
330 		} else
331 			dao_set_cell_printf
332 				(dao, col, 0,
333 				 (info->base.group_by == GROUPED_BY_ROW ?
334 				  _("Row %d") : _("Column %d")),
335 				 source);
336 
337 		switch (info->base.group_by) {
338 		case GROUPED_BY_ROW:
339 			height = value_area_get_width (val, &ep);
340 			mover = &x;
341 			break;
342 		default:
343 			height = value_area_get_height (val, &ep);
344 			mover = &y;
345 			break;
346 		}
347 
348 		expr_input = gnm_expr_new_constant (val);
349 
350 		if (plot != NULL) {
351 			attach_series (plot, gnm_go_data_vector_new_expr (sheet, gnm_expr_top_new
352 									  (gnm_expr_copy (expr_input))));
353 			attach_series (plot, dao_go_data_vector (dao, col, 2, col, height + 1));
354 		}
355 
356 		/*  F(t+1) = F(t) + damp_fact * ( A(t+1) - F(t) ) */
357 
358 		x = 1;
359 		y = 1;
360 		*mover = 5;
361 		dao_set_cell_expr (dao, col, 1, gnm_expr_new_funcall1
362 				   (fd_average,
363 				    analysis_tool_exp_smoothing_funcall5 (fd_offset, gnm_expr_copy (expr_input), 0, 0, y, x)));
364 		x = 1;
365 		y = 1;
366 		(*mover) = 1;
367 		for (row = 1; row <= height; row++, (*mover)++) {
368 			GnmExpr const *A;
369 			GnmExpr const *F;
370 
371 			A = gnm_expr_new_binary (gnm_expr_copy (expr_alpha),
372 						 GNM_EXPR_OP_MULT,
373 						 gnm_expr_new_funcall3
374 						 (fd_index,
375 						  gnm_expr_copy (expr_input),
376 						  gnm_expr_new_constant(value_new_int(y)),
377 						  gnm_expr_new_constant(value_new_int(x))));
378 			F = gnm_expr_new_binary (gnm_expr_new_binary (gnm_expr_new_constant
379 								      (value_new_int (1)),
380 								      GNM_EXPR_OP_SUB,
381 								      gnm_expr_copy (expr_alpha)),
382 						 GNM_EXPR_OP_MULT,
383 						 make_cellref (0, -1));
384 			dao_set_cell_expr (dao, col, row + 1, gnm_expr_new_binary (A, GNM_EXPR_OP_ADD, F));
385 		}
386 
387 		if (info->std_error_flag) {
388 			col++;
389 			dao_set_italic (dao, col, 0, col, 0);
390 			dao_set_cell (dao, col, 0, _("Standard Error"));
391 
392 			y = 0;
393 			x = 0;
394 			(*mover) = 0;
395 			for (row = 1; row <= height+1; row++) {
396 				if (row > 1 && (row - 1 - info->df) > 0) {
397 					GnmExpr const *expr_offset;
398 
399 					if (info->base.group_by == GROUPED_BY_ROW)
400 						delta_x = row - 1;
401 					else
402 						delta_y = row - 1;
403 
404 					expr_offset = analysis_tool_exp_smoothing_funcall5
405 						(fd_offset, gnm_expr_copy (expr_input), y, x, delta_y, delta_x);
406 					dao_set_cell_expr (dao, col, row,
407 							   gnm_expr_new_funcall1
408 							   (fd_sqrt,
409 							    gnm_expr_new_binary
410 							    (gnm_expr_new_funcall2
411 							     (fd_sumxmy2,
412 							      expr_offset,
413 							      make_rangeref (-1, 1 - row, -1, -1)),
414 							     GNM_EXPR_OP_DIV,
415 							     gnm_expr_new_constant (value_new_int
416 										    (row - 1 - info->df)))));
417 				} else
418 					dao_set_cell_na (dao, col, row);
419 			}
420 		}
421 		gnm_expr_free (expr_input);
422 	}
423 
424 	if (so != NULL)
425 		dao_set_sheet_object (dao, 0, 1, so);
426 
427 	gnm_expr_free (expr_alpha);
428 	if (fd_sqrt != NULL)
429 		gnm_func_dec_usage (fd_sqrt);
430 	if (fd_sumxmy2 != NULL)
431 		gnm_func_dec_usage (fd_sumxmy2);
432 	gnm_func_dec_usage (fd_average);
433 	gnm_func_dec_usage (fd_offset);
434 	gnm_func_dec_usage (fd_index);
435 
436 	dao_redraw_respan (dao);
437 
438 	return FALSE;
439 }
440 
441 static gboolean
analysis_tool_exponential_smoothing_engine_des_run(data_analysis_output_t * dao,analysis_tools_data_exponential_smoothing_t * info)442 analysis_tool_exponential_smoothing_engine_des_run (data_analysis_output_t *dao,
443 						analysis_tools_data_exponential_smoothing_t *info)
444 {
445 	GSList *l;
446 	gint col = 0;
447 	gint source;
448 	SheetObject *so = NULL;
449 	GogPlot	     *plot = NULL;
450 	GnmFunc *fd_index;
451 	GnmFunc *fd_offset;
452 	GnmFunc *fd_linest;
453 	GnmFunc *fd_sqrt = NULL;
454 	GnmFunc *fd_sumxmy2 = NULL;
455 	GnmExpr const *expr_alpha = NULL;
456 	GnmExpr const *expr_gamma = NULL;
457 
458 	if (info->std_error_flag) {
459 		fd_sqrt = gnm_func_lookup_or_add_placeholder ("SQRT");
460 		gnm_func_inc_usage (fd_sqrt);
461 		fd_sumxmy2 = gnm_func_lookup_or_add_placeholder ("SUMXMY2");
462 		gnm_func_inc_usage (fd_sumxmy2);
463 	}
464 
465 	fd_linest = gnm_func_lookup_or_add_placeholder ("LINEST");
466 	gnm_func_inc_usage (fd_linest);
467 	fd_index = gnm_func_lookup_or_add_placeholder ("INDEX");
468 	gnm_func_inc_usage (fd_index);
469 	fd_offset = gnm_func_lookup_or_add_placeholder ("OFFSET");
470 	gnm_func_inc_usage (fd_offset);
471 
472 	if (info->show_graph)
473 		create_line_plot (&plot, &so);
474 
475 	dao_set_italic (dao, 0, 0, 0, 0);
476 	dao_set_cell (dao, 0, 0, _("Exponential Smoothing"));
477 
478 	dao_set_format  (dao, 0, 1, 0, 1, _("\"\xce\xb1 =\" * 0.000"));
479 	dao_set_cell_expr (dao, 0, 1, gnm_expr_new_constant (value_new_float (info->damp_fact)));
480 	expr_alpha = dao_get_cellref (dao, 0, 1);
481 
482 	dao_set_format  (dao, 1, 1, 1, 1, _("\"\xce\xb3 =\" * 0.000"));
483 	dao_set_cell_expr (dao, 1, 1, gnm_expr_new_constant (value_new_float (info->g_damp_fact)));
484 	expr_gamma = dao_get_cellref (dao, 1, 1);
485 
486 	dao->offset_row = 2;
487 
488 	for (l = info->base.input, source = 1; l; l = l->next, col++, source++) {
489 		GnmValue *val = value_dup ((GnmValue *)l->data);
490 		GnmValue *val_c = NULL;
491 		GnmExpr const *expr_title = NULL;
492 		GnmExpr const *expr_input = NULL;
493 		gint height;
494 		gint  x = 1;
495 		gint  y = 1;
496 		gint  *mover;
497 		guint delta_x = 1;
498 		guint delta_y = 1;
499 		gint row;
500 		Sheet *sheet;
501 		GnmEvalPos ep;
502 
503 		sheet = val->v_range.cell.a.sheet;
504 		eval_pos_init_sheet (&ep, sheet);
505 
506 		dao_set_italic (dao, col, 0, col, 0);
507 		if (info->base.labels) {
508 			val_c = value_dup (val);
509 			switch (info->base.group_by) {
510 			case GROUPED_BY_ROW:
511 				val->v_range.cell.a.col++;
512 				break;
513 			default:
514 				val->v_range.cell.a.row++;
515 				break;
516 			}
517 			expr_title = gnm_expr_new_funcall1 (fd_index,
518 							    gnm_expr_new_constant (val_c));
519 
520 			dao_set_cell_expr (dao, col, 0, expr_title);
521 		} else
522 			dao_set_cell_printf
523 				(dao, col, 0,
524 				 (info->base.group_by == GROUPED_BY_ROW ?
525 				  _("Row %d") : _("Column %d")),
526 				 source);
527 
528 		switch (info->base.group_by) {
529 		case GROUPED_BY_ROW:
530 			height = value_area_get_width (val, &ep);
531 			mover = &x;
532 			break;
533 		default:
534 			height = value_area_get_height (val, &ep);
535 			mover = &y;
536 			break;
537 		}
538 
539 		expr_input = gnm_expr_new_constant (val);
540 
541 		if (plot != NULL) {
542 			attach_series (plot, gnm_go_data_vector_new_expr (sheet, gnm_expr_top_new
543 									  (gnm_expr_copy (expr_input))));
544 			attach_series (plot, dao_go_data_vector (dao, col, 2, col, height + 1));
545 		}
546 
547 		if (dao_cell_is_visible (dao, col+1, 1))
548 		{
549 			GnmExpr const *expr_linest;
550 
551 			x = 1;
552 			y = 1;
553 			*mover = 5;
554 			expr_linest = gnm_expr_new_funcall1
555 				(fd_linest,
556 				 analysis_tool_exp_smoothing_funcall5 (fd_offset, gnm_expr_copy (expr_input), 0, 0, y, x));
557 			dao_set_cell_expr (dao, col, 1,
558 					   gnm_expr_new_funcall3 (fd_index,
559 								  gnm_expr_copy (expr_linest),
560 								  gnm_expr_new_constant (value_new_int (1)),
561 								  gnm_expr_new_constant (value_new_int (2))));
562 			dao_set_cell_expr (dao, col + 1, 1,
563 					   gnm_expr_new_funcall3 (fd_index,
564 								  expr_linest,
565 								  gnm_expr_new_constant (value_new_int (1)),
566 								  gnm_expr_new_constant (value_new_int (1))));
567 
568 			*mover = 1;
569 			for (row = 1; row <= height; row++, (*mover)++) {
570 				GnmExpr const *LB;
571 				GnmExpr const *A;
572 				GnmExpr const *LL;
573 				GnmExpr const *B;
574 				A = gnm_expr_new_binary (gnm_expr_copy (expr_alpha),
575 							 GNM_EXPR_OP_MULT,
576 							 gnm_expr_new_funcall3
577 							 (fd_index,
578 							  gnm_expr_copy (expr_input),
579 							  gnm_expr_new_constant(value_new_int(y)),
580 							  gnm_expr_new_constant(value_new_int(x))));
581 				LB = gnm_expr_new_binary (gnm_expr_new_binary (gnm_expr_new_constant
582 									       (value_new_int (1)),
583 									       GNM_EXPR_OP_SUB,
584 									       gnm_expr_copy (expr_alpha)),
585 							  GNM_EXPR_OP_MULT,
586 							  gnm_expr_new_binary (make_cellref (0, -1),
587 									       GNM_EXPR_OP_ADD,
588 									       make_cellref (1, -1)));
589 				dao_set_cell_expr (dao, col, row + 1, gnm_expr_new_binary (A, GNM_EXPR_OP_ADD, LB));
590 
591 				LL = gnm_expr_new_binary (gnm_expr_copy (expr_gamma),
592 							  GNM_EXPR_OP_MULT,
593 							  gnm_expr_new_binary (make_cellref (-1, 0),
594 									       GNM_EXPR_OP_SUB,
595 									       make_cellref (-1, -1)));
596 				B = gnm_expr_new_binary (gnm_expr_new_binary (gnm_expr_new_constant
597 									      (value_new_int (1)),
598 									      GNM_EXPR_OP_SUB,
599 									      gnm_expr_copy (expr_gamma)),
600 							 GNM_EXPR_OP_MULT,
601 							 make_cellref (0, -1));
602 				dao_set_cell_expr (dao, col + 1, row + 1, gnm_expr_new_binary (LL, GNM_EXPR_OP_ADD, B));
603 			}
604 
605 			col++;
606 
607 			if (info->std_error_flag) {
608 				col++;
609 				dao_set_italic (dao, col, 0, col, 0);
610 				dao_set_cell (dao, col, 0, _("Standard Error"));
611 
612 				y = 0;
613 				x = 0;
614 				(*mover) = 0;
615 				for (row = 1; row <= height+1; row++) {
616 					if (row > 1 && (row - 1 - info->df) > 0) {
617 						GnmExpr const *expr_offset;
618 
619 						if (info->base.group_by == GROUPED_BY_ROW)
620 							delta_x = row - 1;
621 						else
622 							delta_y = row - 1;
623 
624 						expr_offset = analysis_tool_exp_smoothing_funcall5
625 							(fd_offset, gnm_expr_copy (expr_input), y, x, delta_y, delta_x);
626 
627 						dao_set_cell_expr (dao, col, row,
628 								   gnm_expr_new_funcall1
629 								   (fd_sqrt,
630 								    gnm_expr_new_binary
631 								    (gnm_expr_new_funcall2
632 								     (fd_sumxmy2,
633 								      expr_offset,
634 								      gnm_expr_new_binary(make_rangeref (-2, 1 - row, -2, -1),
635 											  GNM_EXPR_OP_ADD,
636 											  make_rangeref (-1, 1 - row, -1, -1))),
637 								     GNM_EXPR_OP_DIV,
638 								     gnm_expr_new_constant (value_new_int
639 											    (row - 1 - info->df)))));
640 					} else
641 						dao_set_cell_na (dao, col, row);
642 				}
643 			}
644 			gnm_expr_free (expr_input);
645 		} else {
646 			dao_set_cell (dao, col, 1, _("Holt's trend corrected exponential\n"
647 						     "smoothing requires at least 2\n"
648 						     "output columns for each data set."));
649 			dao_set_cell_comment (dao, col, 0, _("Holt's trend corrected exponential\n"
650 							     "smoothing requires at least 2\n"
651 							     "output columns for each data set."));
652 			value_release (val);
653 		}
654 	}
655 
656 	if (so != NULL)
657 		dao_set_sheet_object (dao, 0, 1, so);
658 
659 	gnm_expr_free (expr_alpha);
660 	gnm_expr_free (expr_gamma);
661 	if (fd_sqrt != NULL)
662 		gnm_func_dec_usage (fd_sqrt);
663 	if (fd_sumxmy2 != NULL)
664 		gnm_func_dec_usage (fd_sumxmy2);
665 	gnm_func_dec_usage (fd_linest);
666 	gnm_func_dec_usage (fd_offset);
667 	gnm_func_dec_usage (fd_index);
668 
669 	dao_redraw_respan (dao);
670 
671 	return FALSE;
672 }
673 
674 
675 static gboolean
analysis_tool_exponential_smoothing_engine_ates_run(data_analysis_output_t * dao,analysis_tools_data_exponential_smoothing_t * info)676 analysis_tool_exponential_smoothing_engine_ates_run (data_analysis_output_t *dao,
677 						     analysis_tools_data_exponential_smoothing_t *info)
678 {
679 	GSList *l;
680 	gint col = 0, time, maxheight;
681 	gint source;
682 	SheetObject *so = NULL;
683 	GogPlot	     *plot = NULL;
684 	GnmFunc *fd_index;
685 	GnmFunc *fd_linest;
686 	GnmFunc *fd_average;
687 	GnmFunc *fd_if;
688 	GnmFunc *fd_mod;
689 	GnmFunc *fd_row;
690 	GnmFunc *fd_sqrt = NULL;
691 	GnmFunc *fd_sumxmy2 = NULL;
692 	GnmExpr const *expr_alpha = NULL;
693 	GnmExpr const *expr_gamma = NULL;
694 	GnmExpr const *expr_delta = NULL;
695 
696 	if (info->std_error_flag) {
697 		fd_sqrt = gnm_func_lookup_or_add_placeholder ("SQRT");
698 		gnm_func_inc_usage (fd_sqrt);
699 		fd_sumxmy2 = gnm_func_lookup_or_add_placeholder ("SUMXMY2");
700 		gnm_func_inc_usage (fd_sumxmy2);
701 	}
702 
703 	fd_linest = gnm_func_lookup_or_add_placeholder ("LINEST");
704 	gnm_func_inc_usage (fd_linest);
705 	fd_index = gnm_func_lookup_or_add_placeholder ("INDEX");
706 	gnm_func_inc_usage (fd_index);
707 	fd_average = gnm_func_lookup_or_add_placeholder ("AVERAGE");
708 	gnm_func_inc_usage (fd_average);
709 	fd_if = gnm_func_lookup_or_add_placeholder ("IF");
710 	gnm_func_inc_usage (fd_if);
711 	fd_mod = gnm_func_lookup_or_add_placeholder ("mod");
712 	gnm_func_inc_usage (fd_mod);
713 	fd_row = gnm_func_lookup_or_add_placeholder ("row");
714 	gnm_func_inc_usage (fd_row);
715 
716 	if (info->show_graph)
717 		create_line_plot (&plot, &so);
718 
719 	dao_set_italic (dao, 0, 0, 0, 0);
720 	dao_set_cell (dao, 0, 0, _("Exponential Smoothing"));
721 
722 	dao_set_format  (dao, 2, 0, 2, 0, _("\"\xce\xb1 =\" * 0.000"));
723 	dao_set_cell_expr (dao, 2, 0, gnm_expr_new_constant (value_new_float (info->damp_fact)));
724 	expr_alpha = dao_get_cellref (dao, 2, 0);
725 
726 	dao_set_format  (dao, 3, 0, 3, 0, _("\"\xce\xb3 =\" * 0.000"));
727 	dao_set_cell_expr (dao, 3, 0, gnm_expr_new_constant (value_new_float (info->g_damp_fact)));
728 	expr_gamma = dao_get_cellref (dao, 3, 0);
729 
730 	dao_set_format  (dao, 4, 0, 4, 0, _("\"\xce\xb4 =\" * 0.000"));
731 	dao_set_cell_expr (dao, 4, 0, gnm_expr_new_constant (value_new_float (info->s_damp_fact)));
732 	expr_delta = dao_get_cellref (dao, 4, 0);
733 
734 	dao_set_italic (dao, 0, 2, 0, 2);
735 	dao_set_cell (dao, 0, 2, _("Time"));
736 
737 	maxheight = analysis_tool_calc_length (&info->base);
738 
739 	dao->offset_row = 2 + info->s_period;
740 
741 	for (time = 1 - info->s_period; time <= maxheight; time++)
742 		dao_set_cell_int (dao, 0, time, time);
743 
744 	dao->offset_col = 1;
745 
746 	for (l = info->base.input, source = 1; l; l = l->next, source++) {
747 		GnmValue *val = value_dup ((GnmValue *)l->data);
748 		GnmValue *val_c = NULL;
749 		GnmExpr const *expr_title = NULL;
750 		GnmExpr const *expr_input = NULL;
751 		GnmExpr const *expr_index = NULL;
752 		GnmExpr const *expr_linest;
753 		GnmExpr const *expr_level;
754 		GnmExpr const *expr_trend;
755 		GnmExpr const *expr_season;
756 		GnmExpr const *expr_season_est;
757 		GnmExpr const *expr_data;
758 		GnmExpr const *expr_linest_intercept;
759 		GnmExpr const *expr_linest_slope;
760 		gint height;
761 		GnmEvalPos ep;
762 
763 		eval_pos_init_sheet (&ep, val->v_range.cell.a.sheet);
764 
765 		if (dao_cell_is_visible (dao, col+3, 1))
766 		{
767 			dao_set_italic (dao, col + 1, -info->s_period, col + 3, -info->s_period);
768 			set_cell_text_row (dao, col + 1, -info->s_period, _("/Level"
769 									    "/Trend"
770 									    "/Seasonal Adjustment"));
771 
772 			dao_set_italic (dao, col,  -info->s_period, col,  -info->s_period);
773 			if (info->base.labels) {
774 				val_c = value_dup (val);
775 				switch (info->base.group_by) {
776 				case GROUPED_BY_ROW:
777 					val->v_range.cell.a.col++;
778 					break;
779 				default:
780 					val->v_range.cell.a.row++;
781 					break;
782 				}
783 				expr_title = gnm_expr_new_funcall1 (fd_index,
784 								    gnm_expr_new_constant (val_c));
785 
786 				dao_set_cell_expr (dao, col,  -info->s_period, expr_title);
787 			} else
788 				dao_set_cell_printf
789 					(dao, col,  -info->s_period,
790 					 (info->base.group_by  == GROUPED_BY_ROW ?
791 					  _("Row %d") : _("Column %d")),
792 					 source);
793 
794 
795 			switch (info->base.group_by) {
796 			case GROUPED_BY_ROW:
797 				height = value_area_get_width (val, &ep);
798 				expr_input = gnm_expr_new_constant (val);
799 				expr_index = gnm_expr_new_funcall3 (fd_index, gnm_expr_copy (expr_input),
800 								    gnm_expr_new_constant (value_new_int (1)),
801 								    make_cellref (-1 - col, 0));
802 				break;
803 			default:
804 				height = value_area_get_height (val, &ep);
805 				expr_input = gnm_expr_new_constant (val);
806 				expr_index = gnm_expr_new_funcall3 (fd_index, gnm_expr_copy (expr_input),
807 								    make_cellref (-1 - col, 0),
808 								    gnm_expr_new_constant (value_new_int (1)));
809 				break;
810 			}
811 
812 			expr_data = dao_get_rangeref (dao, col, 1, col, height);
813 			expr_linest = gnm_expr_new_funcall1
814 				(fd_linest, gnm_expr_copy (expr_data));
815 			dao_set_cell_expr (dao, col+1, 0,
816 					   gnm_expr_new_funcall3 (fd_index,
817 								  gnm_expr_copy (expr_linest),
818 								  gnm_expr_new_constant (value_new_int (1)),
819 								  gnm_expr_new_constant (value_new_int (2))));
820 			expr_linest_intercept = dao_get_cellref (dao, col + 1, 0);
821 			dao_set_cell_expr (dao, col + 2, 0,
822 					   gnm_expr_new_funcall3 (fd_index,
823 								  expr_linest,
824 								  gnm_expr_new_constant (value_new_int (1)),
825 								  gnm_expr_new_constant (value_new_int (1))));
826 			expr_linest_slope = dao_get_cellref (dao, col + 2, 0);
827 			expr_level = gnm_expr_new_binary (gnm_expr_new_binary
828 							  (gnm_expr_copy (expr_alpha),
829 							   GNM_EXPR_OP_MULT,
830 							   gnm_expr_new_binary
831 							   (make_cellref (-1,0),
832 							    GNM_EXPR_OP_SUB,
833 							    make_cellref (2,-info->s_period))),
834 							  GNM_EXPR_OP_ADD,
835 							  gnm_expr_new_binary
836 							  (gnm_expr_new_binary
837 							   (gnm_expr_new_constant (value_new_int (1)),
838 							    GNM_EXPR_OP_SUB,
839 							    gnm_expr_copy (expr_alpha)),
840 							   GNM_EXPR_OP_MULT,
841 							   gnm_expr_new_binary
842 							   (make_cellref (0,-1),
843 							    GNM_EXPR_OP_ADD,
844 							    make_cellref (1,-1))));
845 			expr_trend = gnm_expr_new_binary (gnm_expr_new_binary
846 							  (gnm_expr_copy (expr_gamma),
847 							   GNM_EXPR_OP_MULT,
848 							   gnm_expr_new_binary
849 							   (make_cellref (-1,0),
850 							    GNM_EXPR_OP_SUB,
851 							    make_cellref (-1,-1))),
852 							  GNM_EXPR_OP_ADD,
853 							  gnm_expr_new_binary
854 							  (gnm_expr_new_binary
855 							   (gnm_expr_new_constant (value_new_int (1)),
856 							    GNM_EXPR_OP_SUB,
857 							    gnm_expr_copy (expr_gamma)),
858 							   GNM_EXPR_OP_MULT,
859 							   make_cellref (0,-1)));
860 			expr_season = gnm_expr_new_binary (gnm_expr_new_binary
861 							  (gnm_expr_copy (expr_delta),
862 							   GNM_EXPR_OP_MULT,
863 							   gnm_expr_new_binary
864 							   (make_cellref (-3,0),
865 							    GNM_EXPR_OP_SUB,
866 							    make_cellref (-2,0))),
867 							  GNM_EXPR_OP_ADD,
868 							  gnm_expr_new_binary
869 							  (gnm_expr_new_binary
870 							   (gnm_expr_new_constant (value_new_int (1)),
871 							    GNM_EXPR_OP_SUB,
872 							    gnm_expr_copy (expr_delta)),
873 							   GNM_EXPR_OP_MULT,
874 							   make_cellref (0,-info->s_period)));
875 
876 			for (time = 1; time <= maxheight; time++) {
877 				dao_set_cell_expr (dao, col, time, gnm_expr_copy (expr_index));
878 				dao_set_cell_expr (dao, col+1, time, gnm_expr_copy (expr_level));
879 				dao_set_cell_expr (dao, col+2, time, gnm_expr_copy (expr_trend));
880 				dao_set_cell_expr (dao, col+3, time, gnm_expr_copy (expr_season));
881 			}
882 			gnm_expr_free (expr_index);
883 			gnm_expr_free (expr_level);
884 			gnm_expr_free (expr_trend);
885 			gnm_expr_free (expr_season);
886 
887 			if (plot != NULL) {
888 				attach_series (plot, dao_go_data_vector (dao, col, 1, col, height));
889 				attach_series (plot, dao_go_data_vector (dao, col+1, 1, col+1, height));
890 			}
891 
892 			/* We still need to calculate the estimates for the seasonal adjustment. */
893 
894 			expr_season_est = gnm_expr_new_funcall1
895 				(fd_average,
896 				 gnm_expr_new_funcall3
897 				 (fd_if,
898 				  gnm_expr_new_binary
899 				  (gnm_expr_new_funcall2
900 				   (fd_mod,
901 				    gnm_expr_new_binary
902 				    (gnm_expr_new_funcall1
903 				     (fd_row,
904 				      gnm_expr_copy (expr_data)),
905 				     GNM_EXPR_OP_SUB,
906 				     gnm_expr_new_funcall (fd_row, NULL)),
907 				    gnm_expr_new_constant (value_new_int (info->s_period))),
908 				   GNM_EXPR_OP_EQUAL,
909 				   gnm_expr_new_constant (value_new_int (0))),
910 				  gnm_expr_new_binary
911 				  (expr_data,
912 				   GNM_EXPR_OP_SUB,
913 					  gnm_expr_new_binary
914 				  (expr_linest_intercept,
915 				   GNM_EXPR_OP_ADD,
916 				   gnm_expr_new_binary
917 				   (dao_get_rangeref (dao, -1, 1, -1, height),
918 				    GNM_EXPR_OP_MULT,
919 				    expr_linest_slope))),
920 				  gnm_expr_new_constant (value_new_string ("NA"))));
921 
922 			for (time = 0; time > -info->s_period; time--)
923 				dao_set_cell_array_expr (dao, col+3, time, gnm_expr_copy (expr_season_est));
924 
925 			gnm_expr_free (expr_season_est);
926 
927 			col += 4;
928 			if (info->std_error_flag) {
929 				int row;
930 
931 				dao_set_italic (dao, col, - info->s_period, col, - info->s_period);
932 				dao_set_cell (dao, col, - info->s_period, _("Standard Error"));
933 
934 				for (row = 1; row <= height; row++) {
935 					if (row > 1 && (row - info->df) > 0) {
936 						GnmExpr const *expr_stderr;
937 
938 						expr_stderr = gnm_expr_new_funcall1
939 							(fd_sqrt,
940 							 gnm_expr_new_binary
941 							 (gnm_expr_new_funcall2
942 							  (fd_sumxmy2,
943 							   make_rangeref (-4, 1 - row, -4, 0),
944 							   gnm_expr_new_binary
945 							   (make_rangeref (-1, 1 - row - info->s_period,
946 									   -1,  - info->s_period),
947 							    GNM_EXPR_OP_ADD,
948 							    gnm_expr_new_binary
949 							    (make_rangeref (-2, - row, -2, -1),
950 							     GNM_EXPR_OP_ADD,
951 							     make_rangeref (-3, - row, -3, -1)))),
952 							  GNM_EXPR_OP_DIV,
953 							  gnm_expr_new_constant (value_new_int
954 										 (row - info->df))));
955 						dao_set_cell_expr (dao, col, row, expr_stderr);
956 					} else
957 						dao_set_cell_na (dao, col, row);
958 				}
959 				col++;
960 			}
961 			gnm_expr_free (expr_input);
962 		} else {
963 			dao_set_cell (dao, col, 0, _("The additive Holt-Winters exponential\n"
964 						     "smoothing method requires at least 4\n"
965 						     "output columns for each data set."));
966 			dao_set_cell_comment (dao, col, 0, _("The additive Holt-Winters exponential\n"
967 							     "smoothing method requires at least 4\n"
968 							     "output columns for each data set."));
969 			value_release (val);
970 		}
971 	}
972 
973 	if (so != NULL)
974 		dao_set_sheet_object (dao, 0, 1, so);
975 
976 	gnm_expr_free (expr_alpha);
977 	gnm_expr_free (expr_gamma);
978 	gnm_expr_free (expr_delta);
979 	if (fd_sqrt != NULL)
980 		gnm_func_dec_usage (fd_sqrt);
981 	if (fd_sumxmy2 != NULL)
982 		gnm_func_dec_usage (fd_sumxmy2);
983 	gnm_func_dec_usage (fd_linest);
984 	gnm_func_dec_usage (fd_index);
985 	gnm_func_dec_usage (fd_average);
986 	gnm_func_dec_usage (fd_if);
987 	gnm_func_dec_usage (fd_mod);
988 	gnm_func_dec_usage (fd_row);
989 
990 	dao_redraw_respan (dao);
991 
992 	return FALSE;
993 }
994 
995 static gboolean
analysis_tool_exponential_smoothing_engine_mtes_run(data_analysis_output_t * dao,analysis_tools_data_exponential_smoothing_t * info)996 analysis_tool_exponential_smoothing_engine_mtes_run (data_analysis_output_t *dao,
997 						     analysis_tools_data_exponential_smoothing_t *info)
998 {
999 	GSList *l;
1000 	gint col = 0, time, maxheight;
1001 	gint source;
1002 	SheetObject *so = NULL;
1003 	GogPlot	     *plot = NULL;
1004 	GnmFunc *fd_index;
1005 	GnmFunc *fd_offset;
1006 	GnmFunc *fd_linest;
1007 	GnmFunc *fd_average;
1008 	GnmFunc *fd_if;
1009 	GnmFunc *fd_mod;
1010 	GnmFunc *fd_row;
1011 	GnmFunc *fd_sqrt = NULL;
1012 	GnmFunc *fd_sumsq = NULL;
1013 	GnmExpr const *expr_alpha = NULL;
1014 	GnmExpr const *expr_gamma = NULL;
1015 	GnmExpr const *expr_delta = NULL;
1016 
1017 	if (info->std_error_flag) {
1018 		fd_sqrt = gnm_func_lookup_or_add_placeholder ("SQRT");
1019 		gnm_func_inc_usage (fd_sqrt);
1020 		fd_sumsq = gnm_func_lookup_or_add_placeholder ("SUMSQ");
1021 		gnm_func_inc_usage (fd_sumsq);
1022 	}
1023 
1024 	fd_linest = gnm_func_lookup_or_add_placeholder ("LINEST");
1025 	gnm_func_inc_usage (fd_linest);
1026 	fd_index = gnm_func_lookup_or_add_placeholder ("INDEX");
1027 	gnm_func_inc_usage (fd_index);
1028 	fd_offset = gnm_func_lookup_or_add_placeholder ("OFFSET");
1029 	gnm_func_inc_usage (fd_offset);
1030 	fd_average = gnm_func_lookup_or_add_placeholder ("AVERAGE");
1031 	gnm_func_inc_usage (fd_average);
1032 	fd_if = gnm_func_lookup_or_add_placeholder ("IF");
1033 	gnm_func_inc_usage (fd_if);
1034 	fd_mod = gnm_func_lookup_or_add_placeholder ("mod");
1035 	gnm_func_inc_usage (fd_mod);
1036 	fd_row = gnm_func_lookup_or_add_placeholder ("row");
1037 	gnm_func_inc_usage (fd_row);
1038 
1039 	if (info->show_graph)
1040 		create_line_plot (&plot, &so);
1041 
1042 	dao_set_italic (dao, 0, 0, 0, 0);
1043 	dao_set_cell (dao, 0, 0, _("Exponential Smoothing"));
1044 
1045 	dao_set_format  (dao, 2, 0, 2, 0, _("\"\xce\xb1 =\" * 0.000"));
1046 	dao_set_cell_expr (dao, 2, 0, gnm_expr_new_constant (value_new_float (info->damp_fact)));
1047 	expr_alpha = dao_get_cellref (dao, 2, 0);
1048 
1049 	dao_set_format  (dao, 3, 0, 3, 0, _("\"\xce\xb3 =\" * 0.000"));
1050 	dao_set_cell_expr (dao, 3, 0, gnm_expr_new_constant (value_new_float (info->g_damp_fact)));
1051 	expr_gamma = dao_get_cellref (dao, 3, 0);
1052 
1053 	dao_set_format  (dao, 4, 0, 4, 0, _("\"\xce\xb4 =\" * 0.000"));
1054 	dao_set_cell_expr (dao, 4, 0, gnm_expr_new_constant (value_new_float (info->s_damp_fact)));
1055 	expr_delta = dao_get_cellref (dao, 4, 0);
1056 
1057 	dao_set_italic (dao, 0, 2, 0, 2);
1058 	dao_set_cell (dao, 0, 2, _("Time"));
1059 
1060 	maxheight = analysis_tool_calc_length (&info->base);
1061 
1062 	dao->offset_row = 2 + info->s_period;
1063 
1064 	for (time = 1 - info->s_period; time <= maxheight; time++)
1065 		dao_set_cell_int (dao, 0, time, time);
1066 
1067 	dao->offset_col = 1;
1068 
1069 	for (l = info->base.input, source = 1; l; l = l->next, source++) {
1070 		GnmValue *val = value_dup ((GnmValue *)l->data);
1071 		GnmValue *val_c = NULL;
1072 		GnmExpr const *expr_title = NULL;
1073 		GnmExpr const *expr_input = NULL;
1074 		GnmExpr const *expr_index = NULL;
1075 		GnmExpr const *expr_linest;
1076 		GnmExpr const *expr_level;
1077 		GnmExpr const *expr_trend;
1078 		GnmExpr const *expr_season;
1079 		GnmExpr const *expr_season_est;
1080 		GnmExpr const *expr_season_denom;
1081 		GnmExpr const *expr_data;
1082 		GnmExpr const *expr_linest_intercept;
1083 		GnmExpr const *expr_linest_slope;
1084 		gint height, starting_length, i;
1085 		GnmExprList *args = NULL;
1086 		GnmEvalPos ep;
1087 
1088 		eval_pos_init_sheet (&ep, val->v_range.cell.a.sheet);
1089 
1090 		if (dao_cell_is_visible (dao, col+3, 1))
1091 		{
1092 			dao_set_italic (dao, col + 1, -info->s_period, col + 3, -info->s_period);
1093 			set_cell_text_row (dao, col + 1, -info->s_period, _("/Level"
1094 									    "/Trend"
1095 									    "/Seasonal Adjustment"));
1096 
1097 			dao_set_italic (dao, col,  -info->s_period, col,  -info->s_period);
1098 			if (info->base.labels) {
1099 				val_c = value_dup (val);
1100 				switch (info->base.group_by) {
1101 				case GROUPED_BY_ROW:
1102 					val->v_range.cell.a.col++;
1103 					break;
1104 				default:
1105 					val->v_range.cell.a.row++;
1106 					break;
1107 				}
1108 				expr_title = gnm_expr_new_funcall1 (fd_index,
1109 								    gnm_expr_new_constant (val_c));
1110 
1111 				dao_set_cell_expr (dao, col,  -info->s_period, expr_title);
1112 			} else
1113 				dao_set_cell_printf
1114 					(dao, col,  -info->s_period,
1115 					 (info->base.group_by  == GROUPED_BY_ROW ?
1116 					  _("Row %d") : _("Column %d")),
1117 					 source);
1118 
1119 
1120 			switch (info->base.group_by) {
1121 			case GROUPED_BY_ROW:
1122 				height = value_area_get_width (val, &ep);
1123 				expr_input = gnm_expr_new_constant (val);
1124 				expr_index = gnm_expr_new_funcall3 (fd_index, gnm_expr_copy (expr_input),
1125 								    gnm_expr_new_constant (value_new_int (1)),
1126 								    make_cellref (-1 - col, 0));
1127 				break;
1128 			default:
1129 				height = value_area_get_height (val, &ep);
1130 				expr_input = gnm_expr_new_constant (val);
1131 				expr_index = gnm_expr_new_funcall3 (fd_index, gnm_expr_copy (expr_input),
1132 								    make_cellref (-1 - col, 0),
1133 								    gnm_expr_new_constant (value_new_int (1)));
1134 				break;
1135 			}
1136 			starting_length = 4 * info->s_period;
1137 			if (starting_length > height)
1138 				starting_length = height;
1139 			expr_data = analysis_tool_exp_smoothing_funcall5 (fd_offset,
1140 									  dao_get_rangeref (dao, col, 1, col, height),
1141 									  0, 0, starting_length, 1);
1142 			expr_linest = gnm_expr_new_funcall1 (fd_linest, gnm_expr_copy (expr_data));
1143 			dao_set_cell_expr (dao, col+1, 0,
1144 					   gnm_expr_new_funcall3 (fd_index,
1145 								  gnm_expr_copy (expr_linest),
1146 								  gnm_expr_new_constant (value_new_int (1)),
1147 								  gnm_expr_new_constant (value_new_int (2))));
1148 			expr_linest_intercept = dao_get_cellref (dao, col + 1, 0);
1149 			dao_set_cell_expr (dao, col + 2, 0,
1150 					   gnm_expr_new_funcall3 (fd_index,
1151 								  expr_linest,
1152 								  gnm_expr_new_constant (value_new_int (1)),
1153 								  gnm_expr_new_constant (value_new_int (1))));
1154 			expr_linest_slope = dao_get_cellref (dao, col + 2, 0);
1155 			expr_level = gnm_expr_new_binary (gnm_expr_new_binary
1156 							  (gnm_expr_copy (expr_alpha),
1157 							   GNM_EXPR_OP_MULT,
1158 							   gnm_expr_new_binary
1159 							   (make_cellref (-1,0),
1160 							    GNM_EXPR_OP_DIV,
1161 							    make_cellref (2,-info->s_period))),
1162 							  GNM_EXPR_OP_ADD,
1163 							  gnm_expr_new_binary
1164 							  (gnm_expr_new_binary
1165 							   (gnm_expr_new_constant (value_new_int (1)),
1166 							    GNM_EXPR_OP_SUB,
1167 							    gnm_expr_copy (expr_alpha)),
1168 							   GNM_EXPR_OP_MULT,
1169 							   gnm_expr_new_binary
1170 							   (make_cellref (0,-1),
1171 							    GNM_EXPR_OP_ADD,
1172 							    make_cellref (1,-1))));
1173 			expr_trend = gnm_expr_new_binary (gnm_expr_new_binary
1174 							  (gnm_expr_copy (expr_gamma),
1175 							   GNM_EXPR_OP_MULT,
1176 							   gnm_expr_new_binary
1177 							   (make_cellref (-1,0),
1178 							    GNM_EXPR_OP_SUB,
1179 							    make_cellref (-1,-1))),
1180 							  GNM_EXPR_OP_ADD,
1181 							  gnm_expr_new_binary
1182 							  (gnm_expr_new_binary
1183 							   (gnm_expr_new_constant (value_new_int (1)),
1184 							    GNM_EXPR_OP_SUB,
1185 							    gnm_expr_copy (expr_gamma)),
1186 							   GNM_EXPR_OP_MULT,
1187 							   make_cellref (0,-1)));
1188 			expr_season = gnm_expr_new_binary (gnm_expr_new_binary
1189 							  (gnm_expr_copy (expr_delta),
1190 							   GNM_EXPR_OP_MULT,
1191 							   gnm_expr_new_binary
1192 							   (make_cellref (-3,0),
1193 							    GNM_EXPR_OP_DIV,
1194 							    make_cellref (-2,0))),
1195 							  GNM_EXPR_OP_ADD,
1196 							  gnm_expr_new_binary
1197 							  (gnm_expr_new_binary
1198 							   (gnm_expr_new_constant (value_new_int (1)),
1199 							    GNM_EXPR_OP_SUB,
1200 							    gnm_expr_copy (expr_delta)),
1201 							   GNM_EXPR_OP_MULT,
1202 							   make_cellref (0,-info->s_period)));
1203 
1204 			for (time = 1; time <= maxheight; time++) {
1205 				dao_set_cell_expr (dao, col, time, gnm_expr_copy (expr_index));
1206 				dao_set_cell_expr (dao, col+1, time, gnm_expr_copy (expr_level));
1207 				dao_set_cell_expr (dao, col+2, time, gnm_expr_copy (expr_trend));
1208 				dao_set_cell_expr (dao, col+3, time, gnm_expr_copy (expr_season));
1209 			}
1210 			gnm_expr_free (expr_index);
1211 			gnm_expr_free (expr_level);
1212 			gnm_expr_free (expr_trend);
1213 			gnm_expr_free (expr_season);
1214 
1215 			if (plot != NULL) {
1216 				attach_series (plot, dao_go_data_vector (dao, col, 1, col, height));
1217 				attach_series (plot, dao_go_data_vector (dao, col+1, 1, col+1, height));
1218 			}
1219 
1220 			/* We still need to calculate the estimates for the seasonal adjustment. */
1221 			/* = average(if(mod(row(expr_data)-row(),4)=0,expr_data/($E$7+$F$7*$C$8:$C$23),"NA")) */
1222 			for (i = 0; i<info->s_period; i++) {
1223 				expr_season_est = gnm_expr_new_funcall1
1224 					(fd_average,
1225 					 gnm_expr_new_funcall3
1226 					 (fd_if,
1227 					  gnm_expr_new_binary
1228 					  (gnm_expr_new_funcall2
1229 					   (fd_mod,
1230 					    gnm_expr_new_binary
1231 					    (gnm_expr_new_funcall1
1232 					     (fd_row,
1233 					      gnm_expr_copy (expr_data)),
1234 					     GNM_EXPR_OP_SUB,
1235 					     gnm_expr_new_constant (value_new_int (i))),
1236 					    gnm_expr_new_constant (value_new_int (info->s_period))),
1237 					   GNM_EXPR_OP_EQUAL,
1238 					   gnm_expr_new_constant (value_new_int (0))),
1239 					  gnm_expr_new_binary
1240 					  (gnm_expr_copy (expr_data),
1241 					   GNM_EXPR_OP_DIV,
1242 					   gnm_expr_new_binary
1243 					   (gnm_expr_copy (expr_linest_intercept),
1244 					    GNM_EXPR_OP_ADD,
1245 					    gnm_expr_new_binary
1246 					    (analysis_tool_exp_smoothing_funcall5
1247 					     (fd_offset, dao_get_rangeref
1248 					      (dao, -1, 1, -1, height), 0, 0, starting_length, 1),
1249 					     GNM_EXPR_OP_MULT,
1250 					     gnm_expr_copy (expr_linest_slope)))),
1251 					  gnm_expr_new_constant (value_new_string ("NA"))));
1252 				args = gnm_expr_list_prepend (args, expr_season_est);
1253 			}
1254 			expr_season_denom = gnm_expr_new_funcall (fd_average, args);
1255 
1256 			expr_season_est = gnm_expr_new_funcall1
1257 				(fd_average,
1258 				 gnm_expr_new_funcall3
1259 				 (fd_if,
1260 				  gnm_expr_new_binary
1261 				  (gnm_expr_new_funcall2
1262 				   (fd_mod,
1263 				    gnm_expr_new_binary
1264 				    (gnm_expr_new_funcall1
1265 				     (fd_row,
1266 				      gnm_expr_copy (expr_data)),
1267 				     GNM_EXPR_OP_SUB,
1268 				     gnm_expr_new_funcall (fd_row, NULL)),
1269 				    gnm_expr_new_constant (value_new_int (info->s_period))),
1270 				   GNM_EXPR_OP_EQUAL,
1271 				   gnm_expr_new_constant (value_new_int (0))),
1272 				  gnm_expr_new_binary
1273 				  (expr_data,
1274 				   GNM_EXPR_OP_DIV,
1275 				   gnm_expr_new_binary
1276 				   (expr_linest_intercept,
1277 				    GNM_EXPR_OP_ADD,
1278 				    gnm_expr_new_binary
1279 				    (analysis_tool_exp_smoothing_funcall5
1280 				     (fd_offset, dao_get_rangeref
1281 				      (dao, -1, 1, -1, height), 0, 0, starting_length, 1),
1282 				     GNM_EXPR_OP_MULT,
1283 				     expr_linest_slope))),
1284 				  gnm_expr_new_constant (value_new_string ("NA"))));
1285 
1286 			expr_season_est = gnm_expr_new_binary (expr_season_est,
1287 							       GNM_EXPR_OP_DIV,
1288 							       expr_season_denom);
1289 
1290 			for (time = 0; time > -info->s_period; time--)
1291 				dao_set_cell_array_expr (dao, col+3, time, gnm_expr_copy (expr_season_est));
1292 
1293 			gnm_expr_free (expr_season_est);
1294 			col += 4;
1295 			if (info->std_error_flag) {
1296 				int row;
1297 
1298 				dao_set_italic (dao, col, - info->s_period, col, - info->s_period);
1299 				dao_set_cell (dao, col, - info->s_period, _("Standard Error"));
1300 
1301 				for (row = 1; row <= height; row++) {
1302 					if (row > 1 && (row - info->df) > 0) {
1303 						GnmExpr const *expr_stderr;
1304 						GnmExpr const *expr_denom;
1305 
1306 						expr_denom =  gnm_expr_new_binary
1307 							(gnm_expr_new_binary
1308 							 (make_rangeref (-2, - row, -2, -1),
1309 							  GNM_EXPR_OP_ADD,
1310 							  make_rangeref (-3, - row, -3, -1)),
1311 							 GNM_EXPR_OP_MULT,
1312 							 make_rangeref (-1, 1 - row - info->s_period,
1313 									-1,  - info->s_period));
1314 						expr_stderr = gnm_expr_new_funcall1
1315 							(fd_sqrt,
1316 							 gnm_expr_new_binary
1317 							 (gnm_expr_new_funcall1
1318 							  (fd_sumsq,
1319 							   gnm_expr_new_binary
1320 							   (gnm_expr_new_binary
1321 							    (make_rangeref (-4, 1 - row, -4, 0),
1322 							     GNM_EXPR_OP_SUB,
1323 							     gnm_expr_copy (expr_denom)),
1324 							    GNM_EXPR_OP_DIV,
1325 							    expr_denom)),
1326 							  GNM_EXPR_OP_DIV,
1327 							  gnm_expr_new_constant (value_new_int
1328 										 (row - info->df))));
1329 						dao_set_cell_array_expr (dao, col, row, expr_stderr);
1330 					} else
1331 						dao_set_cell_na (dao, col, row);
1332 				}
1333 				col++;
1334 			}
1335 			gnm_expr_free (expr_input);
1336 		} else {
1337 			dao_set_cell (dao, col, 0, _("The multiplicative Holt-Winters exponential\n"
1338 						     "smoothing method requires at least 4\n"
1339 						     "output columns for each data set."));
1340 			dao_set_cell_comment (dao, col, 0, _("The multiplicative Holt-Winters exponential\n"
1341 							     "smoothing method requires at least 4\n"
1342 							     "output columns for each data set."));
1343 			value_release (val);
1344 		}
1345 
1346 	}
1347 
1348 	if (so != NULL)
1349 		dao_set_sheet_object (dao, 0, 1, so);
1350 
1351 	gnm_expr_free (expr_alpha);
1352 	gnm_expr_free (expr_gamma);
1353 	gnm_expr_free (expr_delta);
1354 	if (fd_sqrt != NULL)
1355 		gnm_func_dec_usage (fd_sqrt);
1356 	if (fd_sumsq != NULL)
1357 		gnm_func_dec_usage (fd_sumsq);
1358 	gnm_func_dec_usage (fd_linest);
1359 	gnm_func_dec_usage (fd_offset);
1360 	gnm_func_dec_usage (fd_index);
1361 	gnm_func_dec_usage (fd_average);
1362 	gnm_func_dec_usage (fd_if);
1363 	gnm_func_dec_usage (fd_mod);
1364 	gnm_func_dec_usage (fd_row);
1365 
1366 	dao_redraw_respan (dao);
1367 
1368 	return FALSE;
1369 }
1370 
1371 gboolean
analysis_tool_exponential_smoothing_engine(G_GNUC_UNUSED GOCmdContext * gcc,data_analysis_output_t * dao,gpointer specs,analysis_tool_engine_t selector,gpointer result)1372 analysis_tool_exponential_smoothing_engine (G_GNUC_UNUSED GOCmdContext *gcc, data_analysis_output_t *dao,
1373 					    gpointer specs,
1374 					    analysis_tool_engine_t selector,
1375 					    gpointer result)
1376 {
1377 	analysis_tools_data_exponential_smoothing_t *info = specs;
1378 	int n = 0, m;
1379 
1380 	switch (selector) {
1381 	case TOOL_ENGINE_UPDATE_DESCRIPTOR:
1382 		return (dao_command_descriptor (dao, _("Exponential Smoothing (%s)"), result)
1383 			== NULL);
1384 	case TOOL_ENGINE_UPDATE_DAO:
1385 		prepare_input_range (&info->base.input, info->base.group_by);
1386 		n = 1;
1387 		m = 3 + analysis_tool_calc_length (specs);
1388 		if (info->std_error_flag)
1389 			n++;
1390 		if (info->es_type == exp_smoothing_type_ses_r) {
1391 			m++;
1392 		}
1393 		if (info->es_type == exp_smoothing_type_des) {
1394 			n++;
1395 			m++;
1396 		}
1397 		if (info->es_type == exp_smoothing_type_ates ||
1398 		    info->es_type == exp_smoothing_type_mtes) {
1399 			n += 4;
1400 			m += info->s_period;
1401 		}
1402 		dao_adjust (dao,
1403 			    n * g_slist_length (info->base.input), m);
1404 		return FALSE;
1405 	case TOOL_ENGINE_CLEAN_UP:
1406 		return analysis_tool_generic_clean (specs);
1407 	case TOOL_ENGINE_LAST_VALIDITY_CHECK:
1408 		return FALSE;
1409 	case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
1410 		dao_prepare_output (NULL, dao, _("Exponential Smoothing"));
1411 		return FALSE;
1412 	case TOOL_ENGINE_FORMAT_OUTPUT_RANGE:
1413 		return dao_format_output (dao, _("Exponential Smoothing"));
1414 	case TOOL_ENGINE_PERFORM_CALC:
1415 	default:
1416 		switch (info->es_type) {
1417 		case exp_smoothing_type_mtes:
1418 			return analysis_tool_exponential_smoothing_engine_mtes_run (dao, specs);
1419 		case exp_smoothing_type_ates:
1420 			return analysis_tool_exponential_smoothing_engine_ates_run (dao, specs);
1421 		case exp_smoothing_type_des:
1422 			return analysis_tool_exponential_smoothing_engine_des_run (dao, specs);
1423 		case exp_smoothing_type_ses_r:
1424 			return analysis_tool_exponential_smoothing_engine_ses_r_run (dao, specs);
1425 		case exp_smoothing_type_ses_h:
1426 		default:
1427 			return analysis_tool_exponential_smoothing_engine_ses_h_run (dao, specs);
1428 		}
1429 	}
1430 	return TRUE;  /* We shouldn't get here */
1431 }
1432