static gboolean
analysis_tool_principal_components_engine_run (data_analysis_output_t *dao,
				      analysis_tools_data_generic_t *info)
{
	int l = g_slist_length (info->input), i;
	GSList *inputdata;

	GnmFunc *fd_mean;
	GnmFunc *fd_var;
	GnmFunc *fd_eigen;
	GnmFunc *fd_mmult;
	GnmFunc *fd_munit;
	GnmFunc *fd_sqrt;
	GnmFunc *fd_count;
	GnmFunc *fd_sum;
	GnmFunc *fd_and;
	GnmFunc *fd_if;

	GnmExpr const *expr;
	GnmExpr const *expr_count;
	GnmExpr const *expr_munit;
	GnmExpr const *expr_and;
	
	int data_points;
	GnmExprList *and_args = NULL;

	if (!dao_cell_is_visible (dao, l, 9 + 3 * l)) {
		dao_set_bold (dao, 0, 0, 0, 0);
		dao_set_italic (dao, 0, 0, 0, 0);
		dao_set_cell (dao, 0, 0, 
			      _("Principal components analysis has "
				"insufficient space."));
		return 0;
	}

	fd_mean = gnm_func_lookup_or_add_placeholder 
		("AVERAGE", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_mean);
	fd_var = gnm_func_lookup_or_add_placeholder 
		("VAR", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_var);
	fd_eigen = gnm_func_lookup_or_add_placeholder 
		("EIGEN", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_eigen);
	fd_mmult = gnm_func_lookup_or_add_placeholder 
		("MMULT", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_mmult);
	fd_munit = gnm_func_lookup_or_add_placeholder 
		("MUNIT", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_munit);
	fd_sqrt = gnm_func_lookup_or_add_placeholder 
		("SQRT", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_sqrt);
	fd_count = gnm_func_lookup_or_add_placeholder 
		("COUNT", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_count);
	fd_sum = gnm_func_lookup_or_add_placeholder 
		("SUM", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_sum);
	fd_and = gnm_func_lookup_or_add_placeholder 
		("AND", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_and);
	fd_if = gnm_func_lookup_or_add_placeholder 
		("IF", dao->sheet ? dao->sheet->workbook : NULL, FALSE);
	gnm_func_ref (fd_if);

	dao_set_bold (dao, 0, 0, 0, 0);
	dao_set_italic (dao, 0, 0, 0, 11 + 3 * l);
	dao_set_format (dao, 0, 0, 0, 0, 
			_("\"Principal Components Analysis\";"
			  "[Red]\"Principal Components Analysis is invalid.\""));
	dao_set_align (dao, 0, 0, 0, 0,
		       HALIGN_LEFT, VALIGN_BOTTOM);

	dao->offset_row++;
	analysis_tool_table (dao, info, _("Covariances:"), "COVAR", TRUE);
	dao->offset_row--;

	for (i = 1, inputdata = info->input; inputdata != NULL; i++, inputdata = inputdata->next)
		analysis_tools_write_label (inputdata->data, dao, info, 0, 9 + 2 * l + i, i);

	data_points = value_area_get_width (info->input->data, NULL) * 
		value_area_get_height (info->input->data, NULL);
	for (i = 0; i < l; i++)
		and_args = gnm_expr_list_prepend 
			(and_args, 
			 gnm_expr_new_binary 
			 (gnm_expr_new_constant (value_new_int (data_points)),
			  GNM_EXPR_OP_EQUAL,
			  make_cellref (1 + i, 3 + l)));
	expr_and = gnm_expr_new_funcall	(fd_and, and_args);
	dao_set_cell_expr (dao, 0, 0, 
			   gnm_expr_new_funcall3 
			   (fd_if,
			    expr_and,
			    gnm_expr_new_constant (value_new_int (1)),
			    gnm_expr_new_constant (value_new_int (-1))));
	dao_set_merge (dao,0,0,2,0);
	set_cell_text_col (dao, 0, 3 + l, 
			   _("/Count:"
			     "/Mean:"
			     "/Variance:"
			     "//Eigenvalues:"
			     "/Eigenvectors:"));
	dao_set_cell (dao, 0, 11 + 3 * l, _("Percent of Trace:"));
	dao_set_italic (dao, 0, 9 + 2 * l, 1 + l, 9 + 2 * l);
	dao_set_percent (dao, 1, 11 + 3 * l, 1 + l, 11 + 3 * l);

	for (i = 1, inputdata = info->input; inputdata != NULL; i++, inputdata = inputdata->next) {
		expr = gnm_expr_new_constant (value_dup (inputdata->data));
		
		dao_set_cell_expr (dao, i, 3 + l, 
				   gnm_expr_new_funcall1 (fd_count, gnm_expr_copy (expr)));
		dao_set_cell_expr (dao, i, 4 + l,  
				   gnm_expr_new_funcall1 (fd_mean, gnm_expr_copy (expr)));
		dao_set_cell_expr (dao, i, 5 + l,
				   gnm_expr_new_funcall1 (fd_var, expr));
	}

	expr_count = gnm_expr_new_binary (make_cellref (0,-4), GNM_EXPR_OP_DIV,
					  gnm_expr_new_binary (make_cellref (0,-4), GNM_EXPR_OP_SUB,
							       gnm_expr_new_constant (value_new_int (1))));
	expr = gnm_expr_new_funcall1 
		(fd_eigen, gnm_expr_new_binary 
		 (expr_count, GNM_EXPR_OP_MULT, make_rangeref (0, - (5 + l), l - 1, - 6)));
	dao_set_array_expr (dao, 1, 7 + l, l, l + 1, expr);

	for (i = 1; i <= l; i++) {
		dao_set_align (dao, i, 9 + 2 * l, i, 9 + 2 * l,
			       HALIGN_CENTER, VALIGN_BOTTOM);
		dao_set_cell_printf (dao, i, 9 + 2 * l, "\xce\xbe%i", i);
		dao_set_cell_expr (dao, i, 11 + 3 * l, 
				   gnm_expr_new_binary (make_cellref (0,- 4 - 2 * l),
							GNM_EXPR_OP_DIV,
							gnm_expr_new_funcall1 
							(fd_sum,
							 dao_get_rangeref (dao, 1, 7 + l, l, 7 + l))));
	}

	expr_munit =  gnm_expr_new_funcall1 (fd_munit, gnm_expr_new_constant (value_new_int (l)));
	expr = gnm_expr_new_funcall2 (fd_mmult,
				      gnm_expr_new_binary 
				      (gnm_expr_new_funcall1 
				       (fd_sqrt, gnm_expr_new_binary 
					(gnm_expr_new_constant (value_new_int (1)),
					 GNM_EXPR_OP_DIV, 
					 make_rangeref (0, - 5 - l, l - 1, - 5 - l))),
				       GNM_EXPR_OP_MULT,
				       gnm_expr_copy (expr_munit)),
				      make_rangeref (0, - 2 - l, l - 1, - 3));
	expr = gnm_expr_new_funcall2 (fd_mmult, expr,
				      gnm_expr_new_binary 
				      (gnm_expr_new_funcall1 
				       (fd_sqrt, make_rangeref (0, - 3 - l, l - 1, - 3 - l)),
				       GNM_EXPR_OP_MULT,
				       expr_munit));
	dao_set_array_expr (dao, 1, 10 + 2 * l, l, l, expr);

	gnm_func_unref (fd_mean);
	gnm_func_unref (fd_var);
	gnm_func_unref (fd_eigen);
	gnm_func_unref (fd_mmult);
	gnm_func_unref (fd_munit);
	gnm_func_unref (fd_sqrt);
	gnm_func_unref (fd_count);
	gnm_func_unref (fd_sum);
	gnm_func_unref (fd_and);
	gnm_func_unref (fd_if);

	dao_redraw_respan (dao);
	return 0;
}
static gboolean
analysis_tool_wilcoxon_mann_whitney_engine_run (data_analysis_output_t *dao,
				      analysis_tools_data_generic_b_t *info)
{
	GnmFunc *fd_count;
	GnmFunc *fd_sum;
	GnmFunc *fd_rows;
	GnmFunc *fd_rank_avg;
	GnmFunc *fd_rank;
	GnmFunc *fd_min;
	GnmFunc *fd_normdist;
	GnmFunc *fd_sqrt;
	GnmFunc *fd_if;
	GnmFunc *fd_isblank;

	GnmExpr const *expr_total;
	GnmExpr const *expr_pop_1;
	GnmExpr const *expr_pop_2;
	GnmExpr const *expr_u;
	GnmExpr const *expr_count_total;

	GnmValue *val_1 = value_dup (info->range_1);
	GnmValue *val_2 = value_dup (info->range_2);
	Workbook *wb = dao->sheet ? dao->sheet->workbook : NULL;

	fd_count = gnm_func_lookup_or_add_placeholder ("COUNT");
	gnm_func_ref (fd_count);
	fd_sum = gnm_func_lookup_or_add_placeholder ("SUM");
	gnm_func_ref (fd_sum);
	fd_rows = gnm_func_lookup_or_add_placeholder ("ROWS");
	gnm_func_ref (fd_rows);
	fd_rank_avg = gnm_func_lookup_or_add_placeholder ("RANK.AVG");
	gnm_func_ref (fd_rank_avg);
	fd_rank = gnm_func_lookup_or_add_placeholder ("RANK");
	gnm_func_ref (fd_rank);
	fd_min = gnm_func_lookup_or_add_placeholder ("MIN");
	gnm_func_ref (fd_min);
	fd_normdist = gnm_func_lookup_or_add_placeholder ("NORMDIST");
	gnm_func_ref (fd_normdist);
	fd_sqrt = gnm_func_lookup_or_add_placeholder ("SQRT");
	gnm_func_ref (fd_sqrt);
	fd_if = gnm_func_lookup_or_add_placeholder ("IF");
	gnm_func_ref (fd_if);
	fd_isblank = gnm_func_lookup_or_add_placeholder ("ISBLANK");
	gnm_func_ref (fd_isblank);

	dao_set_italic (dao, 0, 0, 0, 8);
	dao_set_italic (dao, 0, 1, 3, 1);
	dao_set_merge (dao, 0, 0, 3, 0);
	dao_set_cell (dao, 0, 0, _("Wilcoxon-Mann-Whitney Test"));
	set_cell_text_col (dao, 0, 2, _("/Rank-Sum"
					"/N"
					"/U"
					"/Ties"
					"/Statistic"
					"/U-Statistic"
					"/p-Value"));
	dao_set_cell (dao, 3, 1, _("Total"));

	/* Label */
	analysis_tools_write_label_ftest (val_1, dao, 1, 1, info->labels, 1);
	analysis_tools_write_label_ftest (val_2, dao, 2, 1, info->labels, 2);

	expr_total = analysis_tool_combine_area (val_1, val_2, wb);
	expr_pop_1 = gnm_expr_new_constant (val_1);
	expr_pop_2 = gnm_expr_new_constant (val_2);

	/* =sum(if(isblank(region1),0,rank.avg(region1,combined_regions,1))) */

	dao_set_cell_array_expr (dao, 1, 2,
				 gnm_expr_new_funcall1
				 (fd_sum,
				  gnm_expr_new_funcall3
				  (fd_if,
				   gnm_expr_new_funcall1
				  (fd_isblank,
				   gnm_expr_copy (expr_pop_1)),
				   gnm_expr_new_constant (value_new_int (0)),
				   gnm_expr_new_funcall3
				   (fd_rank_avg,
				    gnm_expr_copy (expr_pop_1),
				    gnm_expr_copy (expr_total),
				    gnm_expr_new_constant (value_new_int (1))))));
	dao_set_cell_array_expr (dao, 2, 2,
				 gnm_expr_new_funcall1
				 (fd_sum,
				  gnm_expr_new_funcall3
				  (fd_if,
				   gnm_expr_new_funcall1
				  (fd_isblank,
				   gnm_expr_copy (expr_pop_2)),
				   gnm_expr_new_constant (value_new_int (0)),
				   gnm_expr_new_funcall3
				   (fd_rank_avg,
				    gnm_expr_copy (expr_pop_2),
				    gnm_expr_copy (expr_total),
				    gnm_expr_new_constant (value_new_int (1))))));

	expr_count_total = gnm_expr_new_funcall1
		(fd_count, gnm_expr_copy (expr_total));
	dao_set_cell_expr (dao, 3, 2,
			   gnm_expr_new_binary
			   (gnm_expr_new_binary
			    (gnm_expr_copy (expr_count_total),
			     GNM_EXPR_OP_MULT,
			     gnm_expr_new_binary
			     (gnm_expr_copy (expr_count_total),
			      GNM_EXPR_OP_ADD,
			      gnm_expr_new_constant (value_new_int (1)))),
			    GNM_EXPR_OP_DIV,
			    gnm_expr_new_constant (value_new_int (2))));

	dao_set_cell_expr (dao, 1, 3,
			   gnm_expr_new_funcall1
			   (fd_count,
			    expr_pop_1));
	dao_set_cell_expr (dao, 2, 3,
			   gnm_expr_new_funcall1
			   (fd_count,
			    expr_pop_2));
	dao_set_cell_expr (dao, 3, 3,
			   gnm_expr_new_funcall1
			   (fd_count,
			    gnm_expr_copy (expr_total)));

	expr_u = gnm_expr_new_binary
		(make_cellref (0,- 2), GNM_EXPR_OP_SUB,
		 gnm_expr_new_binary
		 (gnm_expr_new_binary
		  (make_cellref (0,- 1),
		   GNM_EXPR_OP_MULT,
		   gnm_expr_new_binary
		   (make_cellref (0,- 1),
		    GNM_EXPR_OP_ADD,
		    gnm_expr_new_constant (value_new_int (1)))),
		  GNM_EXPR_OP_DIV,
		  gnm_expr_new_constant (value_new_int (2))));

	dao_set_cell_expr (dao, 1, 4, gnm_expr_copy (expr_u));
	dao_set_cell_expr (dao, 2, 4, expr_u);
	dao_set_cell_expr (dao, 3, 4,
			   gnm_expr_new_binary
			   (make_cellref (-2,-1),
			    GNM_EXPR_OP_MULT,
			    make_cellref (-1,-1)));

	dao_set_cell_array_expr (dao, 1, 5,
				 gnm_expr_new_funcall1
				 (fd_sum,
				  gnm_expr_new_binary
				  (gnm_expr_new_funcall2
				   (fd_rank_avg,
				    gnm_expr_copy (expr_total),
				    gnm_expr_copy (expr_total)),
				   GNM_EXPR_OP_SUB,
				   gnm_expr_new_funcall2
				   (fd_rank,
				    gnm_expr_copy (expr_total),
				    gnm_expr_copy (expr_total)))));

	if (dao_cell_is_visible (dao, 2, 4)) {
		GnmExpr const *expr_prod;
		GnmExpr const *expr_sqrt;
		GnmExpr const *expr_normdist;

		expr_prod = gnm_expr_new_binary
			(make_cellref (0,-5),
			 GNM_EXPR_OP_MULT,
			 make_cellref (1,-5));
		expr_sqrt = gnm_expr_new_funcall1
			(fd_sqrt,
			 gnm_expr_new_binary
			 (gnm_expr_new_binary
			  (gnm_expr_copy(expr_prod),
			   GNM_EXPR_OP_MULT,
			   gnm_expr_new_binary
			   (gnm_expr_new_binary
			    (make_cellref (0,-5),
			     GNM_EXPR_OP_ADD,
			     make_cellref (1,-5)),
			    GNM_EXPR_OP_ADD,
			    gnm_expr_new_constant (value_new_int (1)))),
			  GNM_EXPR_OP_DIV,
			  gnm_expr_new_constant (value_new_int (12))));
		expr_normdist = gnm_expr_new_funcall4
			(fd_normdist,
			 make_cellref (0,-1),
			 gnm_expr_new_binary
			 (expr_prod,
			  GNM_EXPR_OP_DIV,
			  gnm_expr_new_constant (value_new_int (2))),
			 expr_sqrt,
			 gnm_expr_new_constant (value_new_bool (TRUE)));

		dao_set_cell_expr (dao, 1, 6,
				   gnm_expr_new_funcall2
				   (fd_min,
				    make_cellref (0,-4),
				    make_cellref (1,-4)));
		dao_set_cell_expr (dao, 1, 7,
				   gnm_expr_new_funcall2
				   (fd_min,
				    make_cellref (0,-3),
				    make_cellref (1,-3)));

		dao_set_cell_expr (dao, 1, 8,
				   gnm_expr_new_binary
				   (gnm_expr_new_constant (value_new_int (2)),
				    GNM_EXPR_OP_MULT,
				    expr_normdist));
		dao_set_cell_comment (dao, 1, 8,
				      _("This p-value is calculated using a\n"
					"normal approximation, so it is\n"
					"only valid for large samples of\n"
					"at least 15 observations in each\n"
					"population, and few if any ties."));
	} else {
		dao_set_cell_na (dao, 1, 6);
		dao_set_cell_comment (dao, 1, 6,
				      _("Since there is insufficient space\n"
					"for the third column of output,\n"
					"this value is not calculated."));
		dao_set_cell_na (dao, 1, 7);
		dao_set_cell_comment (dao, 1, 7,
				      _("Since there is insufficient space\n"
					"for the third column of output,\n"
					"this value is not calculated."));
		dao_set_cell_na (dao, 1, 8);
		dao_set_cell_comment (dao, 1, 8,
				      _("Since there is insufficient space\n"
					"for the third column of output,\n"
					"this value is not calculated."));
	}


	gnm_expr_free (expr_count_total);

	gnm_expr_free (expr_total);

	gnm_func_unref (fd_count);
	gnm_func_unref (fd_sum);
	gnm_func_unref (fd_rows);
	gnm_func_unref (fd_rank_avg);
	gnm_func_unref (fd_rank);
	gnm_func_unref (fd_min);
	gnm_func_unref (fd_normdist);
	gnm_func_unref (fd_sqrt);
	gnm_func_unref (fd_if);
	gnm_func_unref (fd_isblank);

	dao_redraw_respan (dao);
	return 0;
}