[gnumeric] Improve 2 factor ANOVA tool



commit 7757016d7f7af9bd8146c72e69fa1bc366ce723e
Author: Andreas J. Guelzow <aguelzow pyrshep ca>
Date:   Fri Jun 5 01:38:08 2009 -0600

    Improve 2 factor ANOVA tool
    
    2009-06-06  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* Makefile.am: added  analysis-anova.[ch]
    	* analysis-tools.h (analysis_tool_anova_two_factor_engine):
    	  deleted
    	* analysis-tools.c (analysis_tool_anova_two_factor_engine):
    	  deleted
    	(check_data_for_missing): deleted
    	(analysis_tool_anova_two_factor_prepare_input_range): deleted
    	(analysis_tool_anova_two_factor_no_rep_engine_run): deleted
    	(make_label): deleted
    	(analysis_tool_anova_two_factor_engine_run): deleted
    	(analysis_tool_anova_two_factor_engine_clean): moved to
    	  analysis-anova.c
    	(analysis_tool_anova_two_factor_engine): ditto
    	* dao.h (dao_set_border): new
    	* dao.c (dao_set_border): new
    	* analysis-anova.[hc]:new
    
    2009-06-06  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* expr.h (gnm_expr_new_funcall5): new
    	* src/expr.c (gnm_expr_new_funcall5): new
    
    2009-06-02  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* POTFILES.in: added src/tools/analysis-anova.c
    
    2009-06-06  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* dialog-analysis-tools.c (dialog_anova_two_factor_tool): enable
    	  formula/variable selector
---
 ChangeLog                           |    5 +
 NEWS                                |    1 +
 po/ChangeLog                        |    4 +
 po/POTFILES.in                      |    1 +
 src/dialogs/ChangeLog               |    5 +
 src/dialogs/dialog-analysis-tools.c |    3 +-
 src/expr.c                          |   17 +
 src/expr.h                          |    6 +
 src/tools/ChangeLog                 |   19 +
 src/tools/Makefile.am               |    2 +
 src/tools/analysis-anova.c          |  865 +++++++++++++++++++++++++++++++++++
 src/tools/analysis-anova.h          |   56 +++
 src/tools/analysis-tools.c          |  700 +----------------------------
 src/tools/analysis-tools.h          |   37 +--
 src/tools/dao.c                     |   30 ++
 src/tools/dao.h                     |    8 +
 16 files changed, 1027 insertions(+), 732 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 84f057e..35fe21b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-06-06  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* expr.h (gnm_expr_new_funcall5): new
+	* src/expr.c (gnm_expr_new_funcall5): new
+
 2009-06-04  Morten Welinder  <terra gnome org>
 
 	* src/sheet.c (cb_set_cell_content): Fix critical when overwriting
diff --git a/NEWS b/NEWS
index 277b353..340dc0a 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ Andreas:
 	* Remove distinction between label and filled rectangle.
 	* Add superscipt and subscript buttons. [#583327]
 	* Improve ODF import.
+	* Improve 2 factor ANOVA tool
 
 Morten:
 	* Add search-for-number.
diff --git a/po/ChangeLog b/po/ChangeLog
index 06b9f8d..3a9f72d 100644
--- a/po/ChangeLog
+++ b/po/ChangeLog
@@ -1,3 +1,7 @@
+2009-06-02  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* POTFILES.in: added src/tools/analysis-anova.c
+	
 2009-05-23  Morten Welinder <terra gnome org>
 
 	* Release 1.9.8
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1d02c5e..5857d86 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -299,6 +299,7 @@ src/stf-parse.c
 src/stf.c
 src/style.c
 src/test-pango.c
+src/tools/analysis-anova.c
 src/tools/analysis-exp-smoothing.c
 src/tools/analysis-frequency.c
 src/tools/analysis-histogram.c
diff --git a/src/dialogs/ChangeLog b/src/dialogs/ChangeLog
index 33d6059..8971513 100644
--- a/src/dialogs/ChangeLog
+++ b/src/dialogs/ChangeLog
@@ -1,3 +1,8 @@
+2009-06-06  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* dialog-analysis-tools.c (dialog_anova_two_factor_tool): enable
+	  formula/variable selector
+
 2009-06-03  Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* dialog-analysis-tools.c (dialog_ranking_tool): enable formula/variable
diff --git a/src/dialogs/dialog-analysis-tools.c b/src/dialogs/dialog-analysis-tools.c
index 8391133..7eb5bdc 100644
--- a/src/dialogs/dialog-analysis-tools.c
+++ b/src/dialogs/dialog-analysis-tools.c
@@ -28,6 +28,7 @@
 #include <gnumeric.h>
 #include "dialogs.h"
 #include "analysis-tools.h"
+#include "analysis-anova.h"
 #include "analysis-histogram.h"
 #include "analysis-exp-smoothing.h"
 
@@ -3604,7 +3605,7 @@ dialog_anova_two_factor_tool (WBCGtk *wbcg, Sheet *sheet)
 	gnumeric_editable_enters (GTK_WINDOW (state->base.dialog),
 				  GTK_WIDGET (state->replication_entry));
 
-	gnm_dao_set_put (GNM_DAO (state->base.gdao), FALSE, FALSE);
+	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
 	anova_two_factor_tool_update_sensitivity_cb (NULL, state);
 	tool_load_selection ((GenericToolState *)state, FALSE);
 
diff --git a/src/expr.c b/src/expr.c
index b11f91a..c836c56 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -169,6 +169,23 @@ gnm_expr_new_funcall4 (GnmFunc *func,
 	return gnm_expr_new_funcallv (func, 4, argv);
 }
 
+GnmExpr const *
+gnm_expr_new_funcall5 (GnmFunc *func,
+		       GnmExpr const *arg0,
+		       GnmExpr const *arg1,
+		       GnmExpr const *arg2,
+		       GnmExpr const *arg3,
+		       GnmExpr const *arg4)
+{
+	GnmExprConstPtr *argv = g_new (GnmExprConstPtr, 5);
+	argv[0] = arg0;
+	argv[1] = arg1;
+	argv[2] = arg2;
+	argv[3] = arg3;
+	argv[4] = arg4;
+	return gnm_expr_new_funcallv (func, 5, argv);
+}
+
 
 /***************************************************************************/
 
diff --git a/src/expr.h b/src/expr.h
index 6ee851f..c99e48b 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -68,6 +68,12 @@ GnmExpr const *gnm_expr_new_funcall4	(GnmFunc *func,
 					 GnmExpr const *arg1,
 					 GnmExpr const *arg2,
 					 GnmExpr const *arg3);
+GnmExpr const *gnm_expr_new_funcall5	(GnmFunc *func,
+					 GnmExpr const *arg0,
+					 GnmExpr const *arg1,
+					 GnmExpr const *arg2,
+					 GnmExpr const *arg3,
+					 GnmExpr const *arg4);
 GnmExpr const *gnm_expr_new_name	(GnmNamedExpr *name,
 					 Sheet *sheet_scope, Workbook *wb_scope);
 GnmExpr const *gnm_expr_new_cellref	(GnmCellRef const *cr);
diff --git a/src/tools/ChangeLog b/src/tools/ChangeLog
index 06d887c..2af4cc2 100644
--- a/src/tools/ChangeLog
+++ b/src/tools/ChangeLog
@@ -1,3 +1,22 @@
+2009-06-06  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* Makefile.am: added  analysis-anova.[ch]
+	* analysis-tools.h (analysis_tool_anova_two_factor_engine):
+	  deleted
+	* analysis-tools.c (analysis_tool_anova_two_factor_engine):
+	  deleted
+	(check_data_for_missing): deleted
+	(analysis_tool_anova_two_factor_prepare_input_range): deleted
+	(analysis_tool_anova_two_factor_no_rep_engine_run): deleted
+	(make_label): deleted
+	(analysis_tool_anova_two_factor_engine_run): deleted
+	(analysis_tool_anova_two_factor_engine_clean): moved to 
+	  analysis-anova.c
+	(analysis_tool_anova_two_factor_engine): ditto
+	* dao.h (dao_set_border): new
+	* dao.c (dao_set_border): new
+	* analysis-anova.[hc]:new
+
 2009-06-03  Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* analysis-tools.c (analysis_tool_calc_length): also handle
diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am
index f740151..e2af808 100644
--- a/src/tools/Makefile.am
+++ b/src/tools/Makefile.am
@@ -19,6 +19,8 @@ AM_CPPFLAGS = 						\
 noinst_LTLIBRARIES = libtools.la
 
 libtools_la_SOURCES =					\
+	analysis-anova.c			\
+	analysis-anova.h			\
 	analysis-exp-smoothing.c			\
 	analysis-exp-smoothing.h			\
 	analysis-frequency.c				\
diff --git a/src/tools/analysis-anova.c b/src/tools/analysis-anova.c
new file mode 100644
index 0000000..4cda737
--- /dev/null
+++ b/src/tools/analysis-anova.c
@@ -0,0 +1,865 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * analysis-anova.c:
+ *
+ *
+ * Author:
+ *   Andreas J. Guelzow  <aguelzow pyrshep ca>
+ *
+ * (C) Copyright 2009 by Andreas J. Guelzow  <aguelzow pyrshep ca>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gnumeric-config.h>
+#include <glib/gi18n-lib.h>
+#include "gnumeric.h"
+#include "analysis-anova.h"
+#include "analysis-tools.h"
+#include "value.h"
+#include "ranges.h"
+#include "expr.h"
+#include "func.h"
+#include "numbers.h"
+#include "mstyle.h"
+#include "style-border.h"
+#include "style-color.h"
+
+
+static gboolean
+analysis_tool_anova_two_factor_prepare_input_range (
+                       analysis_tools_data_anova_two_factor_t *info)
+{
+	info->rows = info->input->v_range.cell.b.row - info->input->v_range.cell.a.row +
+		(info->labels ? 0 : 1);
+	info->n_r = info->rows/info->replication;
+	info->n_c = info->input->v_range.cell.b.col - info->input->v_range.cell.a.col +
+		(info->labels ? 0 : 1);
+
+	/* Check that correct number of rows per sample */
+	if (info->rows % info->replication != 0) {
+		info->err = analysis_tools_replication_invalid;
+		return TRUE;
+	}
+	
+	/* Check that at least two columns of data are given */
+	if (info->n_c < 2) {
+			info->err = analysis_tools_too_few_cols;
+			return TRUE;
+	}
+	/* Check that at least two data rows of data are given */
+	if (info->n_r < 2) {
+		info->err = analysis_tools_too_few_rows;
+			return TRUE;
+	}
+	
+	return FALSE;
+}
+
+/************* Anova: Two-Factor Without Replication Tool ****************
+ *
+ * The results are given in a table which can be printed out in a new
+ * sheet, in a new workbook, or simply into an existing sheet.
+ *
+ **/
+
+static gboolean
+analysis_tool_anova_two_factor_no_rep_engine_run (data_analysis_output_t *dao,
+						  analysis_tools_data_anova_two_factor_t *info)
+{
+	int        i, r;
+	GnmExpr const *expr_check;
+	GnmExpr const *expr_region;
+	
+	GnmFunc *fd_index;
+	GnmFunc *fd_offset;
+	GnmFunc *fd_count;
+	GnmFunc *fd_sum;
+	GnmFunc *fd_sumsq;
+	GnmFunc *fd_average;
+	GnmFunc *fd_var;
+	GnmFunc *fd_if;
+	GnmFunc *fd_fdist;
+	GnmFunc *fd_finv;
+
+	fd_index = gnm_func_lookup ("INDEX", NULL);
+	gnm_func_ref (fd_index);
+	fd_offset = gnm_func_lookup ("OFFSET", NULL);
+	gnm_func_ref (fd_offset);
+	fd_count = gnm_func_lookup ("COUNT", NULL);
+	gnm_func_ref (fd_count);
+	fd_sum = gnm_func_lookup ("SUM", NULL);
+	gnm_func_ref (fd_sum);
+	fd_sumsq = gnm_func_lookup ("SUMSQ", NULL);
+	gnm_func_ref (fd_sumsq);
+	fd_average = gnm_func_lookup ("AVERAGE", NULL);
+	gnm_func_ref (fd_average);
+	fd_var = gnm_func_lookup ("VAR", NULL);
+	gnm_func_ref (fd_var);
+	fd_if = gnm_func_lookup ("IF", NULL);
+	gnm_func_ref (fd_if);
+	fd_fdist = gnm_func_lookup ("FDIST", NULL);
+	gnm_func_ref (fd_fdist);
+	fd_finv = gnm_func_lookup ("FINV", NULL);
+	gnm_func_ref (fd_finv);
+
+	dao_set_merge (dao, 0, 0, 4, 0);
+	dao_set_italic (dao, 0, 0, 0, 0);
+	dao_set_cell (dao, 0, 0, _("Anova: Two-Factor Without Replication"));
+	dao_set_italic (dao, 0, 2, 4, 2);
+	set_cell_text_row (dao, 0, 2, _("/Summary"
+					"/Count"
+					"/Sum"
+					"/Average"
+					"/Variance"));	
+	r = 3;
+
+	for (i = 1; i <= info->n_r; i++, r++) {
+		GnmExpr const *expr_source;
+		dao_set_italic (dao, 0, r, 0, r);
+		if (info->labels) {
+			GnmExpr const *expr_label;
+			expr_label = gnm_expr_new_funcall3 
+				(fd_index,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (i+1)),
+				 gnm_expr_new_constant (value_new_int (1)));
+			dao_set_cell_expr (dao, 0, r, expr_label);
+			expr_source =  gnm_expr_new_funcall5
+				(fd_offset,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (i)),
+				 gnm_expr_new_constant (value_new_int (1)),
+				 gnm_expr_new_constant (value_new_int (1)),
+				 gnm_expr_new_constant (value_new_int (info->n_c)));
+		} else {
+			dao_set_cell_printf (dao, 0, r, _("Row %i"), i);
+			expr_source =  gnm_expr_new_funcall4
+				(fd_offset,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (i-1)),
+				 gnm_expr_new_constant (value_new_int (0)),
+				 gnm_expr_new_constant (value_new_int (1)));
+		}
+		dao_set_cell_expr (dao, 1, r, gnm_expr_new_funcall1 
+				   (fd_count, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, 2, r, gnm_expr_new_funcall1 
+				   (fd_sum, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, 3, r, gnm_expr_new_funcall1 
+				   (fd_average, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, 4, r, gnm_expr_new_funcall1 
+				   (fd_var, expr_source));
+	}
+	
+	r++;
+
+	for (i = 1; i <= info->n_c; i++, r++) {
+		GnmExpr const *expr_source;
+		dao_set_italic (dao, 0, r, 0, r);
+		if (info->labels) {
+			GnmExpr const *expr_label;
+			expr_label = gnm_expr_new_funcall3 
+				(fd_index,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (1)),
+				 gnm_expr_new_constant (value_new_int (i+1)));
+			dao_set_cell_expr (dao, 0, r, expr_label);
+			expr_source =  gnm_expr_new_funcall5
+				(fd_offset,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (1)),
+				 gnm_expr_new_constant (value_new_int (i)),
+				 gnm_expr_new_constant (value_new_int (info->n_r)),
+				 gnm_expr_new_constant (value_new_int (1)));
+		} else {
+			dao_set_cell_printf (dao, 0, r, _("Column %i"), i);
+			expr_source =  gnm_expr_new_funcall5
+				(fd_offset,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (0)),
+				 gnm_expr_new_constant (value_new_int (i-1)),
+				 gnm_expr_new_constant (value_new_int (info->n_r)),
+				 gnm_expr_new_constant (value_new_int (1)));
+		}
+		dao_set_cell_expr (dao, 1, r, gnm_expr_new_funcall1 
+				   (fd_count, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, 2, r, gnm_expr_new_funcall1 
+				   (fd_sum, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, 3, r, gnm_expr_new_funcall1 
+				   (fd_average, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, 4, r, gnm_expr_new_funcall1 
+				   (fd_var, expr_source));
+	}
+
+	r += 2;
+
+	dao_set_merge (dao, 0, r, 6, r);
+	dao_set_italic (dao, 0, r, 6, r);
+	
+	if (info->labels)
+		expr_region = gnm_expr_new_funcall5
+			(fd_offset, 
+			 gnm_expr_new_constant (value_dup (info->input)),
+			 gnm_expr_new_constant (value_new_int (1)),
+			 gnm_expr_new_constant (value_new_int (1)),
+			 gnm_expr_new_constant (value_new_int (info->n_r)),
+			 gnm_expr_new_constant (value_new_int (info->n_c)));
+	else
+		expr_region = gnm_expr_new_constant (value_dup (info->input));
+
+	expr_check = gnm_expr_new_funcall3 
+		(fd_if, 
+		 gnm_expr_new_binary
+		 (gnm_expr_new_funcall1 
+		  (fd_count, gnm_expr_copy (expr_region)),
+		  GNM_EXPR_OP_EQUAL,
+		  gnm_expr_new_constant (value_new_int (info->n_r*info->n_c))),
+		 gnm_expr_new_constant (value_new_int (1)),
+		 gnm_expr_new_constant (value_new_int (-1)));
+	dao_set_cell_expr (dao, 0, r, expr_check);
+	dao_set_format (dao, 0, r, 0, r, 
+			_("\"ANOVA\";[Red]\"Invalid ANOVA: Missing Observations\""));
+	dao_set_align (dao, 0, r, 0, r, HALIGN_LEFT, VALIGN_BOTTOM);
+		
+	r++;
+	dao_set_italic (dao, 0, r, 0, r + 4);
+	set_cell_text_col (dao, 0, r, _("/Source of Variation"
+					"/Rows"
+					"/Columns"
+					"/Error"
+					"/Total"));
+	dao_set_italic (dao, 1, r, 6, r);
+	dao_set_border (dao, 0, r, 6, r, MSTYLE_BORDER_BOTTOM, GNM_STYLE_BORDER_THICK, 
+			style_color_black (), GNM_STYLE_BORDER_HORIZ);
+	dao_set_border (dao, 0, r+3, 6, r+3, MSTYLE_BORDER_BOTTOM, GNM_STYLE_BORDER_THICK, 
+			style_color_black (), GNM_STYLE_BORDER_HORIZ);
+	set_cell_text_row (dao, 1, r, _("/SS"
+					"/df"
+					"/MS"
+					"/F"
+					"/P-value"
+					"/F critical"));
+
+	dao->offset_col += 1;
+	dao->offset_row += r + 1;
+
+	if (dao_cell_is_visible (dao, 5, 2)) {
+		char *cc;
+		GnmExprList *args;
+
+		GnmExpr const *expr_ms;
+		GnmExpr const *expr_total;
+		GnmExpr const *expr_a;
+		GnmExpr const *expr_b;
+		GnmExpr const *expr_t;
+		GnmExpr const *expr_cf;
+
+		expr_t = gnm_expr_new_funcall1 (fd_sumsq, gnm_expr_copy (expr_region)); 
+		expr_cf = gnm_expr_new_binary 
+			(gnm_expr_new_binary 
+			 (gnm_expr_new_funcall1 (fd_sum, gnm_expr_copy (expr_region)), 
+			  GNM_EXPR_OP_EXP,
+			  gnm_expr_new_constant (value_new_int (2))), 
+			 GNM_EXPR_OP_DIV,
+			 gnm_expr_new_funcall1 (fd_count, gnm_expr_copy (expr_region)));
+		
+		args = NULL;
+		for (i = 1; i <= info->n_r; i++) {
+			GnmExpr const *expr;
+			expr = gnm_expr_new_funcall1 
+				(fd_sum,
+				 gnm_expr_new_funcall5
+				 (fd_offset, 
+				  gnm_expr_new_constant (value_dup (info->input)),
+				  gnm_expr_new_constant (value_new_int 
+							 ((info->labels)?i:(i-1))),
+				  gnm_expr_new_constant (value_new_int 
+							 ((info->labels)?1:0)),
+				  gnm_expr_new_constant (value_new_int (1)),
+				  gnm_expr_new_constant (value_new_int (info->n_c))));
+			args = gnm_expr_list_prepend (args, expr);
+		}
+		expr_a =  gnm_expr_new_binary 
+			(gnm_expr_new_funcall (fd_sumsq, args), GNM_EXPR_OP_DIV,
+			 gnm_expr_new_constant (value_new_int (info->n_c)));
+
+		args = NULL;
+		for (i = 1; i <= info->n_c; i++) {
+			GnmExpr const *expr;
+			expr = gnm_expr_new_funcall1 
+				(fd_sum,
+				 gnm_expr_new_funcall5
+				 (fd_offset, 
+				  gnm_expr_new_constant (value_dup (info->input)),
+				  gnm_expr_new_constant (value_new_int 
+							 ((info->labels)?1:0)),
+				  gnm_expr_new_constant (value_new_int 
+							 ((info->labels)?i:(i-1))),
+				  gnm_expr_new_constant (value_new_int (info->n_r)),
+				  gnm_expr_new_constant (value_new_int (1))));
+			args = gnm_expr_list_prepend (args, expr);
+		}
+		expr_b =  gnm_expr_new_binary 
+			(gnm_expr_new_funcall (fd_sumsq, args), GNM_EXPR_OP_DIV,
+			 gnm_expr_new_constant (value_new_int (info->n_r)));
+		
+		dao_set_cell_expr (dao, 0, 0, gnm_expr_new_binary 
+				   (gnm_expr_copy (expr_a), GNM_EXPR_OP_SUB, 
+				    gnm_expr_copy (expr_cf)));
+		dao_set_cell_expr (dao, 0, 1, gnm_expr_new_binary 
+				   (gnm_expr_copy (expr_b), GNM_EXPR_OP_SUB, 
+				    gnm_expr_copy (expr_cf)));
+		dao_set_cell_expr (dao, 0, 2, gnm_expr_new_binary
+				   (gnm_expr_new_binary 
+				   (expr_t, GNM_EXPR_OP_ADD, expr_cf),
+				   GNM_EXPR_OP_SUB ,
+				    gnm_expr_new_binary 
+				   (expr_a, GNM_EXPR_OP_ADD, expr_b)));
+		expr_total = gnm_expr_new_funcall1 
+			(fd_sum,  make_rangeref (0, -3, 0, -1));
+		dao_set_cell_expr (dao, 0, 3, gnm_expr_copy (expr_total));
+		dao_set_cell_int (dao, 1, 0, info->n_r - 1);
+		dao_set_cell_int (dao, 1, 1, info->n_c - 1);
+		dao_set_cell_expr (dao, 1, 2, gnm_expr_new_binary
+				   (make_cellref (0,-1), GNM_EXPR_OP_MULT, 
+				    make_cellref (0,-2)));
+		dao_set_cell_expr (dao, 1, 3, expr_total);
+
+		expr_ms = gnm_expr_new_binary (make_cellref (-2,0), GNM_EXPR_OP_DIV, 
+					       make_cellref (-1,0));
+		dao_set_cell_expr (dao, 2, 0, gnm_expr_copy (expr_ms));
+		dao_set_cell_expr (dao, 2, 1, gnm_expr_copy (expr_ms));
+		dao_set_cell_expr (dao, 2, 2, expr_ms);
+
+		dao_set_cell_expr (dao, 3, 0,  gnm_expr_new_binary 
+				   (make_cellref (-1,0), GNM_EXPR_OP_DIV, 
+				    make_cellref (-1,2)));
+		dao_set_cell_expr (dao, 3, 1,  gnm_expr_new_binary 
+				   (make_cellref (-1,0), GNM_EXPR_OP_DIV, 
+				    make_cellref (-1,1)));
+		dao_set_cell_expr
+			(dao, 4, 0,
+			 gnm_expr_new_funcall3
+			 (fd_fdist,
+			  make_cellref (-1, 0),
+			  make_cellref (-3, 0),
+			  make_cellref (-3, 2)));
+		dao_set_cell_expr
+			(dao, 4, 1,
+			 gnm_expr_new_funcall3
+			 (fd_fdist,
+			  make_cellref (-1, 0),
+			  make_cellref (-3, 0),
+			  make_cellref (-3, 1)));
+		dao_set_cell_expr
+			(dao, 5, 0,
+			 gnm_expr_new_funcall3
+			 (fd_finv,
+			  gnm_expr_new_constant (value_new_float (info->alpha)),
+			  make_cellref (-4, 0),
+			  make_cellref (-4, 2)));
+		dao_set_cell_expr
+			(dao, 5, 1,
+			 gnm_expr_new_funcall3
+			 (fd_finv,
+			  gnm_expr_new_constant (value_new_float (info->alpha)),
+			  make_cellref (-4, 0),
+			  make_cellref (-4, 1)));
+		cc = g_strdup_printf ("%s = %.2f", "\xce\xb1", info->alpha);
+		dao_set_cell_comment (dao, 5, 0, cc);
+		dao_set_cell_comment (dao, 5, 1, cc);
+		g_free (cc);
+	} else
+		dao_set_cell (dao, 0, 0, _("Insufficient space available for ANOVA table."));
+
+	gnm_func_unref (fd_index);
+	gnm_func_unref (fd_count);
+	gnm_func_unref (fd_offset);
+	gnm_func_unref (fd_sum);
+	gnm_func_unref (fd_sumsq);
+	gnm_func_unref (fd_average);
+	gnm_func_unref (fd_var);
+	gnm_func_unref (fd_if);
+	gnm_func_unref (fd_finv);
+	gnm_func_unref (fd_fdist);
+
+	gnm_expr_free (expr_region);
+
+	dao_redraw_respan (dao);
+
+	return FALSE;
+}
+
+
+/************* Anova: Two-Factor With Replication Tool *******************
+ *
+ * The results are given in a table which can be printed out in a new
+ * sheet, in a new workbook, or simply into an existing sheet.
+ *
+ **/
+
+
+static gboolean
+analysis_tool_anova_two_factor_engine_run (data_analysis_output_t *dao,
+					   analysis_tools_data_anova_two_factor_t *info)
+{
+
+	int        i, k, r;
+	GnmExpr const *expr_check;
+	GnmExpr const *expr_source;
+	GnmExpr const *expr_total_count;
+	
+	GnmFunc *fd_index;
+	GnmFunc *fd_offset;
+	GnmFunc *fd_count;
+	GnmFunc *fd_sum;
+	GnmFunc *fd_sumsq;
+	GnmFunc *fd_average;
+	GnmFunc *fd_var;
+	GnmFunc *fd_if;
+	GnmFunc *fd_fdist;
+	GnmFunc *fd_finv;
+
+	fd_index = gnm_func_lookup ("INDEX", NULL);
+	gnm_func_ref (fd_index);
+	fd_offset = gnm_func_lookup ("OFFSET", NULL);
+	gnm_func_ref (fd_offset);
+	fd_count = gnm_func_lookup ("COUNT", NULL);
+	gnm_func_ref (fd_count);
+	fd_sum = gnm_func_lookup ("SUM", NULL);
+	gnm_func_ref (fd_sum);
+	fd_sumsq = gnm_func_lookup ("SUMSQ", NULL);
+	gnm_func_ref (fd_sumsq);
+	fd_average = gnm_func_lookup ("AVERAGE", NULL);
+	gnm_func_ref (fd_average);
+	fd_var = gnm_func_lookup ("VAR", NULL);
+	gnm_func_ref (fd_var);
+	fd_if = gnm_func_lookup ("IF", NULL);
+	gnm_func_ref (fd_if);
+	fd_fdist = gnm_func_lookup ("FDIST", NULL);
+	gnm_func_ref (fd_fdist);
+	fd_finv = gnm_func_lookup ("FINV", NULL);
+	gnm_func_ref (fd_finv);
+
+	dao_set_merge (dao, 0, 0, 4, 0);
+	dao_set_italic (dao, 0, 0, 0, 0);
+	dao_set_cell (dao, 0, 0, _("Anova: Two-Factor Fixed Effects With Replication"));
+	dao_set_italic (dao, 0, 2, info->n_c + 1, 2);
+	dao_set_cell (dao, 0, 2, _("Summary"));
+
+	for (k = 1; k <= info->n_c; k++) {
+		if (info->labels) {
+			GnmExpr const *expr_label;
+			expr_label = gnm_expr_new_funcall3 
+				(fd_index,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (1)),
+				 gnm_expr_new_constant (value_new_int (k+1)));
+			dao_set_cell_expr (dao, k, 2, expr_label);
+		} else
+		/*xgettext: this is a label for the first, second,... level of factor B in an ANOVA*/
+			dao_set_cell_printf (dao, k, 2, _("B, Level %i"), k);
+	} 
+	dao_set_cell (dao, info->n_c + 1, 2, _("Subtotal"));
+
+	r = 3;
+	for (i = 1; i <= info->n_r; i++, r += 6) {
+		int level_start =  (i-1)*info->replication + 1;
+
+		dao_set_italic (dao, 0, r, 0, r+4);
+		if (info->labels) {
+			GnmExpr const *expr_label;
+			expr_label = gnm_expr_new_funcall3 
+				(fd_index,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (level_start + 1)),
+				 gnm_expr_new_constant (value_new_int (1)));
+			dao_set_cell_expr (dao, 0, r, expr_label);
+		} else
+		/*xgettext: this is a label for the first, second,... level of factor A in an ANOVA*/
+			dao_set_cell_printf (dao, 0, r, _("A, Level %i"), i);
+		set_cell_text_col (dao, 0, r + 1, _("/Count"
+						    "/Sum"
+						    "/Average"
+						    "/Variance"));
+		for (k = 1; k <= info->n_c; k++) {
+			expr_source =  gnm_expr_new_funcall5
+				(fd_offset,
+				 gnm_expr_new_constant (value_dup (info->input)),
+				 gnm_expr_new_constant (value_new_int (level_start)),
+				 gnm_expr_new_constant (value_new_int ((info->labels) ? k : (k - 1))),
+				 gnm_expr_new_constant (value_new_int (info->replication)),
+				 gnm_expr_new_constant (value_new_int (1)));
+			dao_set_cell_expr (dao, k, r + 1, gnm_expr_new_funcall1 
+					   (fd_count, gnm_expr_copy (expr_source)));
+			dao_set_cell_expr (dao, k, r + 2, gnm_expr_new_funcall1 
+					   (fd_sum, gnm_expr_copy (expr_source)));
+			dao_set_cell_expr (dao, k, r + 3, gnm_expr_new_funcall1 
+					   (fd_average, gnm_expr_copy (expr_source)));
+			dao_set_cell_expr (dao, k, r + 4, gnm_expr_new_funcall1 
+					   (fd_var, expr_source));
+		} 
+
+		expr_source =  gnm_expr_new_funcall5
+			(fd_offset,
+			 gnm_expr_new_constant (value_dup (info->input)),
+			 gnm_expr_new_constant (value_new_int (level_start)),
+			 gnm_expr_new_constant (value_new_int ((info->labels) ? 1 : 0)),
+			 gnm_expr_new_constant (value_new_int (info->replication)),
+			 gnm_expr_new_constant (value_new_int (info->n_c)));
+		dao_set_cell_expr (dao, k, r + 1, gnm_expr_new_funcall1 
+				   (fd_count, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, k, r + 2, gnm_expr_new_funcall1 
+				   (fd_sum, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, k, r + 3, gnm_expr_new_funcall1 
+				   (fd_average, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, k, r + 4, gnm_expr_new_funcall1 
+				   (fd_var, expr_source));
+	}
+
+	dao_set_italic (dao, 0, r, 0, r+4);
+	dao_set_cell (dao, 0, r, _("Subtotal"));
+	set_cell_text_col (dao, 0, r + 1, _("/Count"
+					    "/Sum"
+					    "/Average"
+					    "/Variance"));
+
+	for (k = 1; k <= info->n_c; k++) {
+		expr_source =  gnm_expr_new_funcall5
+			(fd_offset,
+			 gnm_expr_new_constant (value_dup (info->input)),
+			 gnm_expr_new_constant (value_new_int (1)),
+			 gnm_expr_new_constant (value_new_int ((info->labels) ? k : (k - 1))),
+			 gnm_expr_new_constant (value_new_int (info->replication * info->n_r)),
+			 gnm_expr_new_constant (value_new_int (1)));
+		dao_set_cell_expr (dao, k, r + 1, gnm_expr_new_funcall1 
+				   (fd_count, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, k, r + 2, gnm_expr_new_funcall1 
+				   (fd_sum, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, k, r + 3, gnm_expr_new_funcall1 
+				   (fd_average, gnm_expr_copy (expr_source)));
+		dao_set_cell_expr (dao, k, r + 4, gnm_expr_new_funcall1 
+				   (fd_var, expr_source));
+	} 
+	
+	dao_set_italic (dao, info->n_c + 1, r, info->n_c + 1, r);
+	dao_set_cell (dao, info->n_c + 1, r, _("Total"));
+	
+	expr_source =  gnm_expr_new_funcall5
+		(fd_offset,
+		 gnm_expr_new_constant (value_dup (info->input)),
+		 gnm_expr_new_constant (value_new_int (1)),
+		 gnm_expr_new_constant (value_new_int ((info->labels) ? 1 : (0))),
+		 gnm_expr_new_constant (value_new_int (info->replication * info->n_r)),
+		 gnm_expr_new_constant (value_new_int (info->n_c)));
+	expr_total_count = gnm_expr_new_funcall1 (fd_count, gnm_expr_copy (expr_source));
+	dao_set_cell_expr (dao, info->n_c + 1, r + 1,  gnm_expr_copy (expr_total_count));
+	dao_set_cell_expr (dao, info->n_c + 1, r + 2, gnm_expr_new_funcall1 
+			   (fd_sum, gnm_expr_copy (expr_source)));
+	dao_set_cell_expr (dao, info->n_c + 1, r + 3, gnm_expr_new_funcall1 
+			   (fd_average, gnm_expr_copy (expr_source)));
+	dao_set_cell_expr (dao, info->n_c + 1, r + 4, gnm_expr_new_funcall1 
+			   (fd_var, gnm_expr_copy (expr_source)));
+
+	r += 7;
+
+	dao_set_merge (dao, 0, r, 6, r);
+	dao_set_italic (dao, 0, r, 6, r);
+	
+	expr_check = gnm_expr_new_funcall3 
+		(fd_if, 
+		 gnm_expr_new_binary
+		 (gnm_expr_copy (expr_total_count),
+		  GNM_EXPR_OP_EQUAL,
+		  gnm_expr_new_constant (value_new_int (info->n_r*info->n_c*info->replication))),
+		 gnm_expr_new_constant (value_new_int (1)),
+		 gnm_expr_new_constant (value_new_int (-1)));
+	dao_set_cell_expr (dao, 0, r, expr_check);
+	dao_set_format (dao, 0, r, 0, r, 
+			_("\"ANOVA\";[Red]\"Invalid ANOVA: Missing Observations\""));
+	dao_set_align (dao, 0, r, 0, r, HALIGN_LEFT, VALIGN_BOTTOM);
+		
+	r++;
+	dao_set_italic (dao, 0, r, 0, r + 5);
+	set_cell_text_col (dao, 0, r, _("/Source of Variation"
+					"/Factor A"
+					"/Factor B"
+					"/Interaction"
+					"/Error"
+					"/Total"));
+	dao_set_italic (dao, 1, r, 6, r);
+	dao_set_border (dao, 0, r, 6, r, MSTYLE_BORDER_BOTTOM, GNM_STYLE_BORDER_THICK, 
+			style_color_black (), GNM_STYLE_BORDER_HORIZ);
+	dao_set_border (dao, 0, r+4, 6, r+4, MSTYLE_BORDER_BOTTOM, GNM_STYLE_BORDER_THICK, 
+			style_color_black (), GNM_STYLE_BORDER_HORIZ);
+	set_cell_text_row (dao, 1, r, _("/SS"
+					"/df"
+					"/MS"
+					"/F"
+					"/P-value"
+					"/F critical"));
+
+	dao->offset_col += 1;
+	dao->offset_row += r + 1;
+
+	if (dao_cell_is_visible (dao, 5, 2)) {
+		char *cc;
+		GnmExprList *args;
+
+		GnmExpr const *expr_ms;
+		GnmExpr const *expr_total;
+		GnmExpr const *expr_a;
+		GnmExpr const *expr_b;
+		GnmExpr const *expr_t;
+		GnmExpr const *expr_s;
+		GnmExpr const *expr_cf;
+
+		expr_t = gnm_expr_new_funcall1 (fd_sumsq, gnm_expr_copy (expr_source));
+		expr_cf = gnm_expr_new_binary
+			(gnm_expr_new_binary
+			 (gnm_expr_new_funcall1 (fd_sum, gnm_expr_copy (expr_source)),
+			  GNM_EXPR_OP_EXP,
+			  gnm_expr_new_constant (value_new_int (2))),
+			 GNM_EXPR_OP_DIV,
+			 gnm_expr_copy (expr_total_count));
+		
+		args = NULL;
+		for (i = 1; i <= info->n_r; i++) {
+			GnmExpr const *expr;
+			int level_start =  (i-1)*info->replication + 1;
+			
+			expr = gnm_expr_new_funcall1
+				(fd_sum,
+				 gnm_expr_new_funcall5
+				 (fd_offset,
+				  gnm_expr_new_constant (value_dup (info->input)),
+				  gnm_expr_new_constant (value_new_int
+							 ((info->labels)?level_start:(level_start-1))),
+				  gnm_expr_new_constant (value_new_int
+							 ((info->labels)?1:0)),
+				  gnm_expr_new_constant (value_new_int (info->replication)),
+				  gnm_expr_new_constant (value_new_int (info->n_c))));
+			args = gnm_expr_list_prepend (args, expr);
+		}
+		expr_a =  gnm_expr_new_binary
+			(gnm_expr_new_funcall (fd_sumsq, args), GNM_EXPR_OP_DIV,
+			 gnm_expr_new_constant (value_new_int (info->n_c * info->replication)));
+
+		args = NULL;
+		for (k = 1; k <= info->n_c; k++) {
+			GnmExpr const *expr;
+			expr = gnm_expr_new_funcall1
+				(fd_sum,
+				 gnm_expr_new_funcall5
+				 (fd_offset,
+				  gnm_expr_new_constant (value_dup (info->input)),
+				  gnm_expr_new_constant (value_new_int
+							 ((info->labels)?1:0)),
+				  gnm_expr_new_constant (value_new_int
+							 ((info->labels)?k:(k-1))),
+				  gnm_expr_new_constant (value_new_int (info->n_r * info->replication)),
+				  gnm_expr_new_constant (value_new_int (1))));
+			args = gnm_expr_list_prepend (args, expr);
+		}
+		expr_b =  gnm_expr_new_binary
+			(gnm_expr_new_funcall (fd_sumsq, args), GNM_EXPR_OP_DIV,
+			 gnm_expr_new_constant (value_new_int (info->n_r * info->replication)));
+
+		args = NULL;
+		for (i = 1; i <= info->n_r; i++) {
+			int level_start =  (i-1)*info->replication + 1;
+			for (k = 1; k <= info->n_c; k++) {
+				GnmExpr const *expr;
+				expr = gnm_expr_new_funcall1
+					(fd_sum,
+					 gnm_expr_new_funcall5
+					 (fd_offset,
+					  gnm_expr_new_constant (value_dup (info->input)),
+					  gnm_expr_new_constant 
+					  (value_new_int ((info->labels)?level_start:level_start-1)),
+					  gnm_expr_new_constant (value_new_int
+								 ((info->labels)?k:(k-1))),
+					  gnm_expr_new_constant (value_new_int (info->replication)),
+					  gnm_expr_new_constant (value_new_int (1))));
+				args = gnm_expr_list_prepend (args, expr);
+			}
+		}
+		expr_s =  gnm_expr_new_binary
+			(gnm_expr_new_funcall (fd_sumsq, args), GNM_EXPR_OP_DIV,
+			 gnm_expr_new_constant (value_new_int (info->replication)));
+		
+		dao_set_cell_expr (dao, 0, 0, gnm_expr_new_binary
+				   (gnm_expr_copy (expr_a), GNM_EXPR_OP_SUB,
+				    gnm_expr_copy (expr_cf)));
+		dao_set_cell_expr (dao, 0, 1, gnm_expr_new_binary
+				   (gnm_expr_copy (expr_b), GNM_EXPR_OP_SUB,
+				    gnm_expr_copy (expr_cf)));
+		dao_set_cell_expr (dao, 0, 2, gnm_expr_new_binary
+				   (gnm_expr_new_binary
+				    (gnm_expr_copy (expr_s), GNM_EXPR_OP_ADD, expr_cf),
+				   GNM_EXPR_OP_SUB ,
+				    gnm_expr_new_binary
+				   (expr_a, GNM_EXPR_OP_ADD, expr_b)));
+		dao_set_cell_expr (dao, 0, 3, gnm_expr_new_binary (expr_t, GNM_EXPR_OP_SUB, expr_s));
+		expr_total = gnm_expr_new_funcall1
+			(fd_sum,  make_rangeref (0, -4, 0, -1));
+		dao_set_cell_expr (dao, 0, 4, gnm_expr_copy (expr_total));
+		dao_set_cell_int (dao, 1, 0, info->n_r - 1);
+		dao_set_cell_int (dao, 1, 1, info->n_c - 1);
+		dao_set_cell_expr (dao, 1, 2, gnm_expr_new_binary
+				   (make_cellref (0,-1), GNM_EXPR_OP_MULT,
+				    make_cellref (0,-2)));
+		dao_set_cell_int (dao, 1, 3, info->n_c*info->n_r*(info->replication - 1));
+		dao_set_cell_expr (dao, 1, 4, expr_total);
+
+		expr_ms = gnm_expr_new_binary (make_cellref (-2,0), GNM_EXPR_OP_DIV,
+					       make_cellref (-1,0));
+		dao_set_cell_expr (dao, 2, 0, gnm_expr_copy (expr_ms));
+		dao_set_cell_expr (dao, 2, 1, gnm_expr_copy (expr_ms));
+		dao_set_cell_expr (dao, 2, 2, gnm_expr_copy (expr_ms));
+		dao_set_cell_expr (dao, 2, 3, expr_ms);
+
+		dao_set_cell_expr (dao, 3, 0,  gnm_expr_new_binary
+				   (make_cellref (-1,0), GNM_EXPR_OP_DIV,
+				    make_cellref (-1,3)));
+		dao_set_cell_expr (dao, 3, 1,  gnm_expr_new_binary
+				   (make_cellref (-1,0), GNM_EXPR_OP_DIV,
+				    make_cellref (-1,2)));
+		dao_set_cell_expr (dao, 3, 2,  gnm_expr_new_binary
+				   (make_cellref (-1,0), GNM_EXPR_OP_DIV,
+				    make_cellref (-1,1)));
+		dao_set_cell_expr
+			(dao, 4, 0,
+			 gnm_expr_new_funcall3
+			 (fd_fdist,
+			  make_cellref (-1, 0),
+			  make_cellref (-3, 0),
+			  make_cellref (-3, 3)));
+		dao_set_cell_expr
+			(dao, 4, 1,
+			 gnm_expr_new_funcall3
+			 (fd_fdist,
+			  make_cellref (-1, 0),
+			  make_cellref (-3, 0),
+			  make_cellref (-3, 2)));
+		dao_set_cell_expr
+			(dao, 4, 2,
+			 gnm_expr_new_funcall3
+			 (fd_fdist,
+			  make_cellref (-1, 0),
+			  make_cellref (-3, 0),
+			  make_cellref (-3, 1)));
+		dao_set_cell_expr
+			(dao, 5, 0,
+			 gnm_expr_new_funcall3
+			 (fd_finv,
+			  gnm_expr_new_constant (value_new_float (info->alpha)),
+			  make_cellref (-4, 0),
+			  make_cellref (-4, 3)));
+		dao_set_cell_expr
+			(dao, 5, 1,
+			 gnm_expr_new_funcall3
+			 (fd_finv,
+			  gnm_expr_new_constant (value_new_float (info->alpha)),
+			  make_cellref (-4, 0),
+			  make_cellref (-4, 2)));
+		dao_set_cell_expr
+			(dao, 5, 2,
+			 gnm_expr_new_funcall3
+			 (fd_finv,
+			  gnm_expr_new_constant (value_new_float (info->alpha)),
+			  make_cellref (-4, 0),
+			  make_cellref (-4, 1)));
+		cc = g_strdup_printf ("%s = %.2f", "\xce\xb1", info->alpha);
+		dao_set_cell_comment (dao, 5, 0, cc);
+		dao_set_cell_comment (dao, 5, 1, cc);
+		dao_set_cell_comment (dao, 5, 2, cc);
+		g_free (cc);
+	} else
+		dao_set_cell (dao, 0, 0, _("Insufficient space available for ANOVA table."));
+
+	gnm_func_unref (fd_index);
+	gnm_func_unref (fd_count);
+	gnm_func_unref (fd_offset);
+	gnm_func_unref (fd_sum);
+	gnm_func_unref (fd_sumsq);
+	gnm_func_unref (fd_average);
+	gnm_func_unref (fd_var);
+	gnm_func_unref (fd_if);
+	gnm_func_unref (fd_finv);
+	gnm_func_unref (fd_fdist);
+
+	gnm_expr_free (expr_source);
+	gnm_expr_free (expr_total_count);
+
+	dao_redraw_respan (dao);
+
+	return FALSE;
+}
+
+static gboolean
+analysis_tool_anova_two_factor_engine_clean (G_GNUC_UNUSED data_analysis_output_t *dao,
+					     gpointer specs)
+{
+	analysis_tools_data_anova_two_factor_t *info = specs;
+
+	if (info->input)
+		value_release (info->input);
+	info->input = NULL;
+
+	return FALSE;
+}
+
+gboolean
+analysis_tool_anova_two_factor_engine (data_analysis_output_t *dao, gpointer specs,
+				   analysis_tool_engine_t selector, gpointer result)
+{
+	analysis_tools_data_anova_two_factor_t *info = specs;
+
+	switch (selector) {
+	case TOOL_ENGINE_UPDATE_DESCRIPTOR:
+		return (dao_command_descriptor (
+				dao, (info->replication == 1) ?
+				_("Two Factor ANOVA (%s), no replication") :
+				_("Two Factor ANOVA (%s),  with replication") , result)
+			== NULL);
+	case TOOL_ENGINE_UPDATE_DAO:
+		if (analysis_tool_anova_two_factor_prepare_input_range (info))
+			return TRUE;
+		if (info->replication == 1)
+			dao_adjust (dao, 7, info->n_c + info->n_r + 12);
+		else
+			dao_adjust (dao, MAX (2 + info->n_c, 7), info->n_r * 6 + 18);
+		return FALSE;
+	case TOOL_ENGINE_CLEAN_UP:
+		return analysis_tool_anova_two_factor_engine_clean (dao, specs);
+	case TOOL_ENGINE_LAST_VALIDITY_CHECK:
+		return FALSE;
+	case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
+		dao_prepare_output (NULL, dao, _("Anova"));
+		return FALSE;
+	case TOOL_ENGINE_FORMAT_OUTPUT_RANGE:
+		return dao_format_output (dao, _("Two Factor ANOVA"));
+	case TOOL_ENGINE_PERFORM_CALC:
+	default:
+		if (info->replication == 1)
+			return analysis_tool_anova_two_factor_no_rep_engine_run (dao, info);
+		else
+			return analysis_tool_anova_two_factor_engine_run (dao, info);
+	}
+	return TRUE;  /* We shouldn't get here */
+}
+
diff --git a/src/tools/analysis-anova.h b/src/tools/analysis-anova.h
new file mode 100644
index 0000000..14cf4cb
--- /dev/null
+++ b/src/tools/analysis-anova.h
@@ -0,0 +1,56 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * analysis-anova.h:
+ *
+ * Author:
+ *   Andreas J. Guelzow  <aguelzow pyrshep ca>
+ *
+ * (C) Copyright 2009 by Andreas J. Guelzow  <aguelzow pyrshep ca>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef ANALYSIS_ANOVA_H
+#define ANALYSIS_ANOVA_H
+
+#include "gnumeric.h"
+#include "numbers.h"
+#include "dao.h"
+#include "tools.h"
+#include "analysis-tools.h"
+
+/****************  2-Factor ANOVA  ***************/
+/*** with contingency table like data provision **/
+
+typedef struct {
+	analysis_tools_error_code_t err;
+	WorkbookControl *wbc;
+	GnmValue     *input;
+	group_by_t group_by;
+	gboolean   labels;
+	gnm_float alpha;
+	gint       replication;
+	gint       rows;
+	gint       n_c;
+	gint       n_r;
+} analysis_tools_data_anova_two_factor_t;
+
+gboolean analysis_tool_anova_two_factor_engine (data_analysis_output_t *dao, gpointer specs,
+					   analysis_tool_engine_t selector, gpointer result);
+
+
+#endif
diff --git a/src/tools/analysis-tools.c b/src/tools/analysis-tools.c
index 4fe4b62..bfd863e 100644
--- a/src/tools/analysis-tools.c
+++ b/src/tools/analysis-tools.c
@@ -580,26 +580,6 @@ gnm_check_input_range_list_homogeneity (GSList *input_range)
 	return state.hom;
 }
 
-/*
- *  check_data_for_missing:
- *  @data:
- *
- *  Check whether any data is missing
- *
- */
-static gboolean
-check_data_for_missing (GPtrArray *data)
-{
-	guint i;
-
-	for (i = 0; i < data->len; i++) {
-		data_set_t *this_data = g_ptr_array_index (data, i);
-		if (this_data->missing != NULL)
-			return TRUE;
-	}
-
-	return FALSE;
-}
 
 /***** Some general routines ***********************************************/
 
@@ -1666,8 +1646,7 @@ analysis_tool_ztest_engine_run (data_analysis_output_t *dao,
 		  gnm_expr_new_funcall1
 		  (fd_normsinv,
 		   gnm_expr_new_constant
-		   (value_new_float (info->base.alpha))
-			  )));
+		   (value_new_float (info->base.alpha)))));
 
 	/* P (T<=t) two-tail */
 	dao_set_cell_expr
@@ -3931,7 +3910,6 @@ analysis_tool_ranking_engine_run (data_analysis_output_t *dao,
 
 		expr_rank = gnm_expr_new_funcall2 (fd_rank,
 						   make_cellref (-1,0),
-/* 						   make_rangeref (-1, 0, -1, rows - 1), */
 						   gnm_expr_new_constant (value_dup (val_org)));
 		if (info->av_ties) {
 			GnmExpr const *expr_rank_lower;
@@ -3950,7 +3928,6 @@ analysis_tool_ranking_engine_run (data_analysis_output_t *dao,
 			expr_rank_lower = gnm_expr_new_funcall3
 				(fd_rank,
 				 make_cellref (-1,0),
-/* 				 make_rangeref (-1, 0, -1, rows - 1), */
 				 gnm_expr_new_constant (value_dup (val_org)),
 				 gnm_expr_new_constant (value_new_int (1)));
 			expr_rank = gnm_expr_new_binary
@@ -3962,8 +3939,6 @@ analysis_tool_ranking_engine_run (data_analysis_output_t *dao,
 			
 			gnm_func_unref (fd_count);
 		}
-/* 		dao_set_array_expr (dao, 2, 2, 1, rows, expr_rank); */
-
 		expr_percentile = gnm_expr_new_funcall3 (fd_percentrank,
 							 gnm_expr_new_constant (value_dup (val_org)),
 							 make_cellref (-2,0),
@@ -4359,679 +4334,6 @@ analysis_tool_anova_single_engine (data_analysis_output_t *dao, gpointer specs,
 }
 
 
-
-/************* Anova: Two-Factor Without Replication Tool ****************
- *
- * The results are given in a table which can be printed out in a new
- * sheet, in a new workbook, or simply into an existing sheet.
- *
- **/
-
-static gboolean
-analysis_tool_anova_two_factor_prepare_input_range (
-                       analysis_tools_data_anova_two_factor_t *info)
-{
-	info->row_input_range = NULL;
-	info->col_input_range = NULL;
-
-	info->rows = info->input->v_range.cell.b.row - info->input->v_range.cell.a.row +
-		(info->labels ? 0 : 1);
-	info->n_r = info->rows/info->replication;
-	info->n_c = info->input->v_range.cell.b.col - info->input->v_range.cell.a.col +
-		(info->labels ? 0 : 1);
-
-	if (info->replication == 1) {
-		info->row_input_range = g_slist_prepend (NULL, value_dup (info->input));
-		prepare_input_range (&info->row_input_range, GROUPED_BY_ROW);
-		if (info->labels) {
-			GSList *list = info->row_input_range;
-			info->row_input_range = g_slist_remove_link (info->row_input_range, list);
-			range_list_destroy (list);
-		}
-		info->col_input_range = g_slist_prepend (NULL, info->input);
-		prepare_input_range (&info->col_input_range, GROUPED_BY_COL);
-		if (info->labels) {
-			GSList *list = info->col_input_range;
-			info->col_input_range = g_slist_remove_link (info->col_input_range, list);
-			range_list_destroy (list);
-		}
-		info->input = NULL;
-		if (info->col_input_range == NULL || info->row_input_range == NULL ||
-		    info->col_input_range->next == NULL || info->row_input_range->next == NULL) {
-			range_list_destroy (info->col_input_range);
-			info->col_input_range = NULL;
-			range_list_destroy (info->row_input_range);
-			info->row_input_range = NULL;
-			info->err = analysis_tools_missing_data;
-			return TRUE;
-		}
-	} else {
-		/* Check that correct number of rows per sample */
-		if (info->rows % info->replication != 0) {
-			info->err = analysis_tools_replication_invalid;
-			return TRUE;
-		}
-
-		/* Check that at least two columns of data are given */
-		if (info->n_c < 2) {
-			info->err = analysis_tools_too_few_cols;
-			return TRUE;
-		}
-		/* Check that at least two data rows of data are given */
-		if (info->n_r < 2) {
-			info->err = analysis_tools_too_few_rows;
-			return TRUE;
-		}
-
-		if (info->labels) {
-			info->input->v_range.cell.a.row += 1;
-			info->input->v_range.cell.a.col += 1;
-		}
-
-	}
-	return FALSE;
-}
-
-static gboolean
-analysis_tool_anova_two_factor_no_rep_engine_run (data_analysis_output_t *dao,
-						  analysis_tools_data_anova_two_factor_t *info)
-{
-	GPtrArray *row_data = NULL;
-	GPtrArray *col_data = NULL;
-
-	int        i, n, error;
-	int        cols;
-	int        rows;
-	gnm_float    cm,  sum = 0;
-	gnm_float    ss_r = 0, ss_c = 0, ss_e = 0, ss_t = 0;
-	gnm_float    ms_r, ms_c, ms_e, f1, f2, p1, p2, f1_c, f2_c;
-	int        df_r, df_c, df_e, df_t;
-
-
-	row_data = new_data_set_list (info->row_input_range, GROUPED_BY_ROW,
-				  FALSE, info->labels, dao->sheet);
-	col_data = new_data_set_list (info->col_input_range, GROUPED_BY_COL,
-				  FALSE, info->labels, dao->sheet);
-	if (check_data_for_missing (row_data) ||
-	    check_data_for_missing (col_data)) {
-		destroy_data_set_list (row_data);
-		destroy_data_set_list (col_data);
-		gnm_cmd_context_error_calc (GO_CMD_CONTEXT (info->wbc),
-			_("The input range contains non-numeric data."));
-		return TRUE;
-	}
-
-	cols = col_data->len;
-	rows = row_data->len;
-	n = rows * cols;
-
-	dao_set_cell (dao, 0, 0, _("Anova: Two-Factor Without Replication"));
-	set_cell_text_row (dao, 0, 2, _("/SUMMARY"
-					"/Count"
-					"/Sum"
-					"/Average"
-					"/Variance"));
-
-	for (i = 0; i < rows; i++) {
-	        gnm_float v;
-		data_set_t *data_set = g_ptr_array_index (row_data, i);
-		gnm_float *the_data = (gnm_float *)data_set->data->data;
-
-		dao_set_cell (dao, 0, i + 3, data_set->label);
-		dao_set_cell_int (dao, 1, i + 3, data_set->data->len);
-		error = gnm_range_sum (the_data, data_set->data->len, &v);
-		sum +=  v;
-		ss_r += v * v/ data_set->data->len;
-		dao_set_cell_float_na (dao, 2, i + 3, v, error == 0);
-		dao_set_cell_float_na (dao, 3, i + 3,  v / data_set->data->len,
-				   error == 0 && data_set->data->len != 0);
-		error = gnm_range_var_est (the_data, data_set->data->len , &v);
-		dao_set_cell_float_na (dao, 4, i + 3, v, error == 0);
-
-		error = gnm_range_sumsq (the_data, data_set->data->len, &v);
-		ss_t += v;
-	}
-
-	for (i = 0; i < cols; i++) {
-	        gnm_float v;
-		data_set_t *data_set = g_ptr_array_index (col_data, i);
-		gnm_float *the_data = (gnm_float *)data_set->data->data;
-
-		dao_set_cell (dao, 0, i + 4 + rows, data_set->label);
-		dao_set_cell_int (dao, 1, i + 4 + rows, data_set->data->len);
-		error = gnm_range_sum (the_data, data_set->data->len, &v);
-		ss_c += v * v/ data_set->data->len;
-		dao_set_cell_float_na (dao, 2, i + 4 + rows, v, error == 0);
-		dao_set_cell_float_na (dao, 3, i + 4 + rows, v / data_set->data->len,
-				   error == 0 && data_set->data->len != 0);
-		error = gnm_range_var_est (the_data, data_set->data->len , &v);
-		dao_set_cell_float_na (dao, 4, i + 4 + rows, v, error == 0);
-	}
-
-	cm = sum * sum / n;
-	ss_t -= cm;
-	ss_r -= cm;
-	ss_c -= cm;
-	ss_e = ss_t - ss_r - ss_c;
-
-
-	df_r = rows - 1;
-	df_c = cols - 1;
-	df_e = (rows - 1) * (cols - 1);
-	df_t = n - 1;
-	ms_r = ss_r / df_r;
-	ms_c = ss_c / df_c;
-	ms_e = ss_e / df_e;
-	f1   = ms_r / ms_e;
-	f2   = ms_c / ms_e;
-	p1   = pf (f1, df_r, df_e, FALSE, FALSE);
-	p2   = pf (f2, df_c, df_e, FALSE, FALSE);
-	f1_c = qf (info->alpha, df_r, df_e, FALSE, FALSE);
-	f2_c = qf (info->alpha, df_c, df_e, FALSE, FALSE);
-
-	set_cell_text_col (dao, 0, 6 + rows + cols, _("/ANOVA"
-						      "/Source of Variation"
-						      "/Rows"
-						      "/Columns"
-						      "/Error"
-						      "/Total"));
-	set_cell_text_row (dao, 1, 7 + rows + cols, _("/SS"
-						      "/df"
-						      "/MS"
-						      "/F"
-						      "/P-value"
-						      "/F critical"));
-
-	dao_set_cell_float (dao, 1, 8 + rows + cols, ss_r);
-	dao_set_cell_float (dao, 1, 9 + rows + cols, ss_c);
-	dao_set_cell_float (dao, 1, 10 + rows + cols, ss_e);
-	dao_set_cell_float (dao, 1, 11 + rows + cols, ss_t);
-	dao_set_cell_int (dao, 2, 8 + rows + cols, df_r);
-	dao_set_cell_int (dao, 2, 9 + rows + cols, df_c);
-	dao_set_cell_int (dao, 2, 10 + rows + cols, df_e);
-	dao_set_cell_int (dao, 2, 11 + rows + cols, df_t);
-	dao_set_cell_float (dao, 3, 8 + rows + cols, ms_r);
-	dao_set_cell_float (dao, 3, 9 + rows + cols, ms_c);
-	dao_set_cell_float (dao, 3, 10 + rows + cols, ms_e);
-	dao_set_cell_float_na (dao, 4, 8 + rows + cols, f1, ms_e != 0);
-	dao_set_cell_float_na (dao, 4, 9 + rows + cols, f2, ms_e != 0);
-	dao_set_cell_float_na (dao, 5, 8 + rows + cols, p1, ms_e != 0);
-	dao_set_cell_float_na (dao, 5, 9 + rows + cols, p2, ms_e != 0);
-	dao_set_cell_float (dao, 6, 8 + rows + cols, f1_c);
-	dao_set_cell_float (dao, 6, 9 + rows + cols, f2_c);
-
-	dao_set_italic (dao, 1, 2, 4, 2);
-	dao_set_italic (dao, 1, 7 + rows + cols, 6, 7 + rows + cols);
-	dao_set_italic (dao, 0, 0, 0, 11 + rows + cols);
-
-	destroy_data_set_list (row_data);
-	destroy_data_set_list (col_data);
-
-	return FALSE;
-}
-
-
-/************* Anova: Two-Factor With Replication Tool *******************
- *
- * The results are given in a table which can be printed out in a new
- * sheet, in a new workbook, or simply into an existing sheet.
- *
- **/
-
-static char *
-make_label (Sheet *sheet, int col, int row, char *default_format, int index,
-	    gboolean read_cell)
-{
-	char *rendered_text = NULL;
-	if (read_cell) {
-		GnmCell *cell = sheet_cell_get (sheet, col, row);
-		if (cell && cell->value)
-			rendered_text = value_get_as_string (cell->value);
-	}
-	if (rendered_text != NULL) {
-		if (strlen (rendered_text) == 0)
-			g_free (rendered_text);
-		else
-			return rendered_text;
-	}
-	return g_strdup_printf (default_format, index);
-}
-
-static gboolean
-analysis_tool_anova_two_factor_engine_run (data_analysis_output_t *dao,
-					   analysis_tools_data_anova_two_factor_t *info)
-{
-	guint i_c, i_r;
-	guint n = 0;
-	GPtrArray *col_labels = NULL;
-	GPtrArray *row_labels = NULL;
-	GPtrArray *row_data = NULL;
-	GnmValue *input_cp;
-	gint df_r, df_c, df_rc, df_e, df_total;
-	gnm_float ss_r = 0.0, ss_c = 0.0, ss_rc = 0.0, ss_e = 0.0, ss_total = 0.0;
-	gnm_float ms_r, ms_c, ms_rc, ms_e;
-	gnm_float f_r, f_c, f_rc;
-	gnm_float p_r, p_c, p_rc;
-	gnm_float cm = 0.0;
-	guint max_sample_size = 0;
-	guint missing_observations = 0;
-	gboolean empty_sample = FALSE;
-	gboolean return_value = FALSE;
-
-
-	col_labels = g_ptr_array_new ();
-	g_ptr_array_set_size (col_labels, info->n_c);
-	for (i_c = 0; i_c < info->n_c; i_c++)
-		g_ptr_array_index (col_labels, i_c) = make_label (
-			dao->sheet, info->input->v_range.cell.a.col + i_c,
-			info->input->v_range.cell.a.row - 1,
-			_("Column %i"), i_c + 1, info->labels);
-	row_labels = g_ptr_array_new ();
-	g_ptr_array_set_size (row_labels, info->n_r);
-	for (i_r = 0; i_r < info->n_r; i_r++)
-		g_ptr_array_index (row_labels, i_r) = make_label (
-			dao->sheet,
-			info->input->v_range.cell.a.col - 1,
-			info->input->v_range.cell.a.row + i_r * info->replication,
-			_("Row %i"), i_r + 1, info->labels);
-
-	input_cp = value_dup (info->input);
-	input_cp->v_range.cell.b.row = input_cp->v_range.cell.a.row +
-		info->replication - 1;
-	row_data = g_ptr_array_new ();
-	while (input_cp->v_range.cell.a.row < info->input->v_range.cell.b.row) {
-		GPtrArray *col_data = NULL;
-		GSList *col_input_range = NULL;
-
-		col_input_range = g_slist_prepend (NULL, value_dup (input_cp));
-		prepare_input_range (&col_input_range, GROUPED_BY_COL);
-		col_data = new_data_set_list (col_input_range, GROUPED_BY_COL,
-				  TRUE, FALSE, dao->sheet);
-		g_ptr_array_add (row_data, col_data);
-		range_list_destroy (col_input_range);
-		input_cp->v_range.cell.a.row += info->replication;
-		input_cp->v_range.cell.b.row += info->replication;
-	}
-	value_release (input_cp);
-
-/* We have loaded the data, we should now check for missing observations */
-
-	for (i_r = 0; i_r < info->n_r; i_r++) {
-		GPtrArray *data = NULL;
-
-		data = g_ptr_array_index (row_data, i_r);
-		for (i_c = 0; i_c < info->n_c; i_c++) {
-			data_set_t *cell_data = g_ptr_array_index (data, i_c);
-			guint num = cell_data->data->len;
-			if (num == 0)
-				empty_sample = TRUE;
-			else {
-				if (num > max_sample_size)
-					max_sample_size = num;
-				missing_observations += (info->replication - num);
-			}
-		}
-	}
-
-	if (empty_sample) {
-		gnm_cmd_context_error_calc (GO_CMD_CONTEXT (info->wbc),
-				 _("One of the factor combinations does not contain "
-				   "any observations!"));
-		return_value =  TRUE;
-		goto anova_two_factor_with_r_tool_end;
-	}
-
-	missing_observations -= ((info->replication - max_sample_size) * info->n_c * info->n_r);
-
-/* We are ready to create the summary table */
-	dao_set_cell (dao, 0, 0, _("Anova: Two-Factor With Replication"));
-	dao_set_cell (dao, 0, 2, _("SUMMARY"));
-	for (i_c = 0; i_c < info->n_c; i_c++)
-		dao_set_cell (dao, 1 + i_c, 2,
-			 (char *)g_ptr_array_index (col_labels, i_c));
-	dao_set_cell (dao, 1 + info->n_c, 2, _("Total"));
-	for (i_r = 0; i_r <= info->n_r; i_r++) {
-		set_cell_text_col (dao, 0, 4 + i_r * 6, _("/Count"
-							"/Sum"
-							"/Average"
-							"/Variance"));
-		if (i_r < info->n_r)
-			dao_set_cell (dao, 0, 3 + i_r * 6,
-				  (char *)g_ptr_array_index (row_labels, i_r));
-	}
-	dao_set_cell (dao, 0, 3 + info->n_r * 6, _("Total"));
-
-	set_cell_text_col (dao, 0, info->n_r * 6 + 10, _("/ANOVA"
-						    "/Source of Variation"
-						    "/Rows"
-						    "/Columns"
-						    "/Interaction"
-						    "/Within"));
-	dao_set_cell (dao, 0, info->n_r * 6 + 17, _("Total"));
-
-	set_cell_text_row (dao, 1,  info->n_r * 6 + 11, _("/SS"
-						    "/df"
-						    "/MS"
-						    "/F"
-						    "/P-value"
-						    "/F critical"));
-
-	for (i_r = 0; i_r < info->n_r; i_r++) {
-		GPtrArray *data = NULL;
-		gnm_float row_sum = 0.0;
-		gnm_float row_sum_sq = 0.0;
-		guint row_cnt = 0;
-
-		data = g_ptr_array_index (row_data, i_r);
-		for (i_c = 0; i_c < info->n_c; i_c++) {
-			data_set_t *cell_data;
-			gnm_float v;
-			int error;
-			int num;
-			gnm_float *the_data;
-
-			cell_data = g_ptr_array_index (data, i_c);
-			the_data = (gnm_float *)cell_data->data->data;
-			num = cell_data->data->len;
-			row_cnt += num;
-
-			dao_set_cell_int (dao, 1 + i_c, 4 + i_r * 6, num);
-			error = gnm_range_sum (the_data, num, &v);
-			row_sum += v;
-			ss_rc += v * v / num;
-			dao_set_cell_float_na (dao, 1 + i_c, 5 + i_r * 6, v, error == 0);
-			dao_set_cell_float_na (dao, 1 + i_c, 6 + i_r * 6, v / num,
-					   error == 0 && num > 0);
-			error = gnm_range_var_est (the_data, num , &v);
-			dao_set_cell_float_na (dao, 1 + i_c, 7 + i_r * 6, v, error == 0);
-
-			error = gnm_range_sumsq (the_data, num, &v);
-			row_sum_sq += v;
-		}
-		cm += row_sum;
-		n += row_cnt;
-		ss_r += row_sum * row_sum / row_cnt;
-		ss_total += row_sum_sq;
-		dao_set_cell_int (dao, 1 + info->n_c, 4 + i_r * 6, row_cnt);
-		dao_set_cell_float (dao, 1 + info->n_c, 5 + i_r * 6, row_sum);
-		dao_set_cell_float (dao, 1 + info->n_c, 6 + i_r * 6, row_sum / row_cnt);
-		dao_set_cell_float (dao, 1 + info->n_c, 7 + i_r * 6,
-				(row_sum_sq - row_sum * row_sum / row_cnt) / (row_cnt - 1));
-	}
-
-	for (i_c = 0; i_c < info->n_c; i_c++) {
-		gnm_float col_sum = 0.0;
-		gnm_float col_sum_sq = 0.0;
-		guint col_cnt = 0;
-
-		for (i_r = 0; i_r < info->n_r; i_r++) {
-			data_set_t *cell_data;
-			gnm_float v;
-			int error;
-			gnm_float *the_data;
-			GPtrArray *data = NULL;
-
-			data = g_ptr_array_index (row_data, i_r);
-			cell_data = g_ptr_array_index (data, i_c);
-			the_data = (gnm_float *)cell_data->data->data;
-
-			col_cnt += cell_data->data->len;
-			error = gnm_range_sum (the_data, cell_data->data->len, &v);
-			col_sum += v;
-
-			error = gnm_range_sumsq (the_data, cell_data->data->len, &v);
-			col_sum_sq += v;
-		}
-		ss_c += col_sum * col_sum / col_cnt;
-		dao_set_cell_int (dao, 1 + i_c, 4 + info->n_r * 6, col_cnt);
-		dao_set_cell_float (dao, 1 + i_c, 5 + info->n_r * 6, col_sum);
-		dao_set_cell_float (dao, 1 + i_c, 6 + info->n_r * 6, col_sum / col_cnt);
-		dao_set_cell_float (dao, 1 + i_c, 7 + info->n_r * 6,
-				(col_sum_sq - col_sum * col_sum / col_cnt) / (col_cnt - 1));
-	}
-
-	dao_set_cell_int (dao, 1 + info->n_c, 4 + info->n_r * 6, n);
-	dao_set_cell_float (dao, 1 + info->n_c, 5 + info->n_r * 6, cm);
-	dao_set_cell_float (dao, 1 + info->n_c, 6 + info->n_r * 6, cm / n);
-	cm = cm * cm/ n;
-	dao_set_cell_float   (dao, 1 + info->n_c, 7 + info->n_r * 6, (ss_total - cm) / (n - 1));
-
-	df_r = info->n_r - 1;
-	df_c = info->n_c - 1;
-	df_rc = df_r * df_c;
-	df_total = n - 1;
-	df_e = df_total - df_rc - df_c - df_r;
-
-	if (missing_observations > 0) {
-		/* Oh bother: there is some data missing which means we have to: */
-		/* -- Estimate the missing values                                */
-                /* -- Recalculate the values obtained towards the SS             */
-		/* We couldn't do that above because the Summary table should    */
-                /* contain the real values                                       */
-
-		/* Estimate the missing values */
-
-		for (i_r = 0; i_r < info->n_r; i_r++) {
-			GPtrArray *data = NULL;
-
-			data = g_ptr_array_index (row_data, i_r);
-			for (i_c = 0; i_c < info->n_c; i_c++) {
-				data_set_t *cell_data;
-				guint num, error;
-
-				cell_data = g_ptr_array_index (data, i_c);
-				num = cell_data->data->len;
-				if (num < max_sample_size) {
-					gnm_float *the_data, v;
-					guint i;
-
-					the_data = (gnm_float *)cell_data->data->data;
-					error = gnm_range_average (the_data, num, &v);
-					for (i = num; i < max_sample_size; i++)
-						g_array_append_val (cell_data->data, v);
-				}
-			}
-		}
-
-		/* Recalculate the values obtained towards the SS */
-
-		ss_r = 0;
-		ss_c = 0;
-		ss_rc = 0;
-		ss_total = 0;
-		cm = 0;
-		n = 0;
-
-		for (i_r = 0; i_r < info->n_r; i_r++) {
-			GPtrArray *data = NULL;
-			gnm_float row_sum = 0.0;
-			gnm_float row_sum_sq = 0.0;
-			guint row_cnt = 0;
-
-			data = g_ptr_array_index (row_data, i_r);
-			for (i_c = 0; i_c < info->n_c; i_c++) {
-				data_set_t *cell_data;
-				gnm_float v;
-				int error;
-				int num;
-				gnm_float *the_data;
-
-				cell_data = g_ptr_array_index (data, i_c);
-				the_data = (gnm_float *)cell_data->data->data;
-				num = cell_data->data->len;
-				row_cnt += num;
-
-				error = gnm_range_sum (the_data, num, &v);
-				row_sum += v;
-				ss_rc += v * v / num;
-
-				error = gnm_range_sumsq (the_data, num, &v);
-				row_sum_sq += v;
-			}
-			cm += row_sum;
-			n += row_cnt;
-			ss_r += row_sum * row_sum / row_cnt;
-			ss_total += row_sum_sq;
-		}
-
-		for (i_c = 0; i_c < info->n_c; i_c++) {
-			gnm_float col_sum = 0.0;
-			guint col_cnt = 0;
-
-			for (i_r = 0; i_r < info->n_r; i_r++) {
-				data_set_t *cell_data;
-				gnm_float v;
-				int error;
-				gnm_float *the_data;
-				GPtrArray *data = NULL;
-
-				data = g_ptr_array_index (row_data, i_r);
-				cell_data = g_ptr_array_index (data, i_c);
-				the_data = (gnm_float *)cell_data->data->data;
-
-				col_cnt += cell_data->data->len;
-				error = gnm_range_sum (the_data, cell_data->data->len, &v);
-				col_sum += v;
-			}
-			ss_c += col_sum * col_sum / col_cnt;
-		}
-
-		cm = cm * cm/ n;
-	}
-
-	ss_r = ss_r - cm;
-	ss_c = ss_c - cm;
-	ss_rc = ss_rc - ss_r - ss_c - cm;
-	ss_total = ss_total - cm;
-	ss_e = ss_total - ss_r - ss_c - ss_rc;
-
-	dao_set_cell_float (dao, 1, info->n_r * 6 + 12, ss_r);
-	dao_set_cell_float (dao, 1, info->n_r * 6 + 13, ss_c);
-	dao_set_cell_float (dao, 1, info->n_r * 6 + 14, ss_rc);
-	dao_set_cell_float (dao, 1, info->n_r * 6 + 15, ss_e);
-	dao_set_cell_float (dao, 1, info->n_r * 6 + 17, ss_total);
-
-	dao_set_cell_int   (dao, 2, info->n_r * 6 + 12, df_r);
-	dao_set_cell_int   (dao, 2, info->n_r * 6 + 13, df_c);
-	dao_set_cell_int   (dao, 2, info->n_r * 6 + 14, df_rc);
-	dao_set_cell_int   (dao, 2, info->n_r * 6 + 15, df_e);
-	dao_set_cell_int   (dao, 2, info->n_r * 6 + 17, df_total);
-
-	ms_r = ss_r / df_r;
-	ms_c = ss_c / df_c;
-	ms_rc = ss_rc / df_rc;
-	ms_e = ss_e / df_e;
-
-	dao_set_cell_float_na (dao, 3, info->n_r * 6 + 12, ms_r, df_r > 0);
-	dao_set_cell_float_na (dao, 3, info->n_r * 6 + 13, ms_c, df_c > 0);
-	dao_set_cell_float_na (dao, 3, info->n_r * 6 + 14, ms_rc, df_rc > 0);
-	dao_set_cell_float_na (dao, 3, info->n_r * 6 + 15, ms_e, df_e > 0);
-
-	f_r = ms_r / ms_e;
-	f_c = ms_c / ms_e;
-	f_rc = ms_rc / ms_e;
-
-	dao_set_cell_float_na (dao, 4, info->n_r * 6 + 12, f_r, ms_e != 0 && df_r > 0);
-	dao_set_cell_float_na (dao, 4, info->n_r * 6 + 13, f_c, ms_e != 0 && df_c > 0);
-	dao_set_cell_float_na (dao, 4, info->n_r * 6 + 14, f_rc, ms_e != 0 && df_rc > 0);
-
-	p_r = pf (f_r, df_r, df_e, FALSE, FALSE);
-	p_c = pf (f_c, df_c, df_e, FALSE, FALSE);
-	p_rc = pf (f_rc, df_rc, df_e, FALSE, FALSE);
-
-	dao_set_cell_float_na (dao, 5, info->n_r * 6 + 12, p_r, ms_e != 0 && df_r > 0 && df_e > 0);
-	dao_set_cell_float_na (dao, 5, info->n_r * 6 + 13, p_c, ms_e != 0 && df_c > 0 && df_e > 0);
-	dao_set_cell_float_na (dao, 5, info->n_r * 6 + 14, p_rc, ms_e != 0 && df_rc > 0 && df_e > 0);
-
-	dao_set_cell_float_na (dao, 6, info->n_r * 6 + 12,
-			   qf (info->alpha, df_r, df_e, FALSE, FALSE),
-			   df_r > 0 && df_e > 0);
-	dao_set_cell_float_na (dao, 6, info->n_r * 6 + 13,
-			   qf (info->alpha, df_c, df_e, FALSE, FALSE),
-			   df_c > 0 && df_e > 0);
-	dao_set_cell_float_na (dao, 6, info->n_r * 6 + 14,
-			   qf (info->alpha, df_rc, df_e, FALSE, FALSE),
-			   df_rc > 0 && df_e > 0);
-
-	dao_set_italic (dao, 0, info->n_r * 6 + 11, 6, info->n_r * 6 + 11);
-	dao_set_italic (dao, 0, 2, 1 + info->n_c, 2);
-	dao_set_italic (dao, 0, 0, 0, 17 + info->n_r * 6);
-
- anova_two_factor_with_r_tool_end:
-
-	for (i_r = 0; i_r < row_data->len; i_r++)
-		destroy_data_set_list (g_ptr_array_index (row_data, i_r));
-	g_ptr_array_free (row_data, TRUE);
-
-	for (i_c = 0; i_c < info->n_c; i_c++)
-		g_free (g_ptr_array_index (col_labels, i_c));
-	g_ptr_array_free (col_labels, TRUE);
-	for (i_r = 0; i_r < info->n_r; i_r++)
-		g_free (g_ptr_array_index (row_labels, i_r));
-	g_ptr_array_free (row_labels, TRUE);
-
-	return return_value;
-}
-
-static gboolean
-analysis_tool_anova_two_factor_engine_clean (G_GNUC_UNUSED data_analysis_output_t *dao,
-					     gpointer specs)
-{
-	analysis_tools_data_anova_two_factor_t *info = specs;
-
-	range_list_destroy (info->col_input_range);
-	info->col_input_range = NULL;
-	range_list_destroy (info->row_input_range);
-	info->row_input_range = NULL;
-	if (info->input)
-		value_release (info->input);
-	info->input = NULL;
-
-	return FALSE;
-}
-
-gboolean
-analysis_tool_anova_two_factor_engine (data_analysis_output_t *dao, gpointer specs,
-				   analysis_tool_engine_t selector, gpointer result)
-{
-	analysis_tools_data_anova_two_factor_t *info = specs;
-
-	switch (selector) {
-	case TOOL_ENGINE_UPDATE_DESCRIPTOR:
-		return (dao_command_descriptor (
-				dao, (info->replication == 1) ?
-				_("Two Factor ANOVA (%s), no replication") :
-				_("Two Factor ANOVA (%s),  with replication") , result)
-			== NULL);
-	case TOOL_ENGINE_UPDATE_DAO:
-		if (analysis_tool_anova_two_factor_prepare_input_range (info))
-			return TRUE;
-		if (info->replication == 1)
-			dao_adjust (dao, 7, info->n_c + info->n_r + 12);
-		else
-			dao_adjust (dao, MAX (2 + info->n_c, 7), info->n_r * 6 + 18);
-		return FALSE;
-	case TOOL_ENGINE_CLEAN_UP:
-		return analysis_tool_anova_two_factor_engine_clean (dao, specs);
-	case TOOL_ENGINE_LAST_VALIDITY_CHECK:
-		return FALSE;
-	case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
-		dao_prepare_output (NULL, dao, _("Anova"));
-		return FALSE;
-	case TOOL_ENGINE_FORMAT_OUTPUT_RANGE:
-		return dao_format_output (dao, _("Two Factor ANOVA"));
-	case TOOL_ENGINE_PERFORM_CALC:
-	default:
-		if (info->replication == 1)
-			return analysis_tool_anova_two_factor_no_rep_engine_run (dao, info);
-		else
-			return analysis_tool_anova_two_factor_engine_run (dao, info);
-	}
-	return TRUE;  /* We shouldn't get here */
-}
-
-
-
 /************* Fourier Analysis Tool **************************************
  *
  * This tool performes a fast fourier transform calculating the fourier
diff --git a/src/tools/analysis-tools.h b/src/tools/analysis-tools.h
index f70fac3..f100e3c 100644
--- a/src/tools/analysis-tools.h
+++ b/src/tools/analysis-tools.h
@@ -8,14 +8,9 @@
 #include "regression.h"
 #include "complex.h"
 
-/*******************************************************************/
-/* Section 1: gui utility functions for the tools                  */
-
-/*******************************************************************/
-/* Section 2: not undoable tools                                   */
 
 /*******************************************************************/
-/* Section 3: Undoable tools and their data structures             */
+/* Section 1: Undoable tools and their data structures             */
 
 typedef enum {
 	analysis_tools_noerr = 0,
@@ -29,7 +24,7 @@ typedef enum {
 
 
 /********************************************************************/
-/* Subsection 3a: Undoable Tools using the first  common generic data struct */
+/* Section 2: Undoable Tools using the first  common generic data struct */
 
 typedef struct {
 	analysis_tools_error_code_t err;
@@ -52,7 +47,7 @@ gboolean analysis_tool_covariance_engine  (data_analysis_output_t *dao, gpointer
 
 
 /********************************************************************/
-/* Subsection 3b: Undoable Tools using the first  common generic    */
+/* Section 3: Undoable Tools using the first  common generic    */
 /*                data struct augmented with some simple fields     */
 
 /************** Single Factor ANOVA  *************/
@@ -148,7 +143,7 @@ gboolean analysis_tool_ranking_engine (data_analysis_output_t *dao, gpointer spe
 
 
 /********************************************************************/
-/* Subsection 3c: Undoable Tools using the second common generic    */
+/* Section 4: Undoable Tools using the second common generic    */
 /*                data struct augmented with some simple fields     */
 
 /*********************** FTest ************************/
@@ -206,31 +201,9 @@ gboolean analysis_tool_ztest_engine (data_analysis_output_t *dao, gpointer specs
 				     analysis_tool_engine_t selector, gpointer result);
 
 
-/********************************************************************/
-/* Subsection 3d: Undoable Tools using their own data struct        */
-
-/****************  2-Factor ANOVA  ***************/
-
-typedef struct {
-	analysis_tools_error_code_t err;
-	WorkbookControl *wbc;
-	GnmValue     *input;
-	group_by_t group_by;
-	gboolean   labels;
-	GSList    *row_input_range;
-	GSList    *col_input_range;
-	gnm_float alpha;
-	gint       replication;
-	gint       rows;
-	guint       n_c;
-	guint       n_r;
-} analysis_tools_data_anova_two_factor_t;
-
-gboolean analysis_tool_anova_two_factor_engine (data_analysis_output_t *dao, gpointer specs,
-					   analysis_tool_engine_t selector, gpointer result);
 
 /********************************************************************/
-/* Functions also needed elsewhere.                                 */
+/* Section 5     Functions also needed elsewhere.                  */
 
 gboolean analysis_tool_generic_clean (gpointer specs);
 gboolean analysis_tool_generic_b_clean (gpointer specs);
diff --git a/src/tools/dao.c b/src/tools/dao.c
index 07f03bc..81f99f1 100644
--- a/src/tools/dao.c
+++ b/src/tools/dao.c
@@ -43,6 +43,7 @@
 #include "sheet-merge.h"
 #include "sheet-object-cell-comment.h"
 #include "style-color.h"
+#include "style-border.h"
 #include "graph.h"
 #include <goffice/app/go-doc.h>
 #include <goffice/utils/go-glib-extras.h>
@@ -875,6 +876,35 @@ dao_set_align (data_analysis_output_t *dao, int col1, int row1,
 	dao_set_style (dao, col1, row1, col2, row2, mstyle);
 }
 
+/**
+ * dao_set_border:
+ * @dao:
+ * @col1:
+ * @row1:
+ * @col2:
+ * @row2:
+ *
+ *
+ *
+ **/
+void
+dao_set_border (data_analysis_output_t *dao, int col1, int row1,
+	       int col2, int row2,
+		GnmStyleElement elem, GnmStyleBorderType border,
+		GnmColor *color,
+		GnmStyleBorderOrientation orientation)
+{
+	GnmStyle *mstyle;
+
+	mstyle = gnm_style_new ();
+	gnm_style_set_border (mstyle, elem, 
+			      gnm_style_border_fetch (border,
+						      color, 
+						      orientation));
+	dao_set_style (dao, col1, row1, col2, row2, mstyle);
+}
+
+
 
 /**
  * dao_get_colrow_state_list:
diff --git a/src/tools/dao.h b/src/tools/dao.h
index fe3a497..d977339 100644
--- a/src/tools/dao.h
+++ b/src/tools/dao.h
@@ -32,6 +32,9 @@
 #include "numbers.h"
 #include "style.h"
 #include <goffice/data/goffice-data.h>
+#include "style-color.h"
+#include "style-border.h"
+#include "graph.h"
 
 typedef enum {
         NewSheetOutput, NewWorkbookOutput, RangeOutput, InPlaceOutput
@@ -86,6 +89,11 @@ void dao_set_colors (data_analysis_output_t *dao, int col1, int row1,
 void dao_set_align (data_analysis_output_t *dao, int col1, int row1,
 		    int col2, int row2,
 		    GnmHAlign align_h, GnmVAlign align_v);
+void dao_set_border (data_analysis_output_t *dao, int col1, 
+		     int row1, int col2, int row2,
+		     GnmStyleElement elem,GnmStyleBorderType border,
+		     GnmColor *color,
+		     GnmStyleBorderOrientation orientation);
 void dao_set_cell             (data_analysis_output_t *dao, int col, int row,
 			       char const *text);
 void dao_set_cell_printf      (data_analysis_output_t *dao,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]