[gnumeric] Regression: add and use new LEVERAGE function.



commit 5ed961f03579d3ea06992b7c1f87453555486f0a
Author: Morten Welinder <terra gnome org>
Date:   Thu Jan 17 19:10:43 2013 -0500

    Regression: add and use new LEVERAGE function.
    
    This avoids using m-times-m matrices where m is the number of observations.

 NEWS                          |    1 +
 configure.ac                  |    2 +-
 plugins/fn-math/ChangeLog     |    4 +++
 plugins/fn-math/functions.c   |   58 +++++++++++++++++++++++++++++++++++++++++
 plugins/fn-math/plugin.xml.in |    1 +
 src/regression.h              |    2 +
 src/tools/ChangeLog           |    5 +++
 src/tools/analysis-tools.c    |   38 ++++----------------------
 8 files changed, 78 insertions(+), 33 deletions(-)
---
diff --git a/NEWS b/NEWS
index cd97c7a..dfdfdf7 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,7 @@ Morten:
 	* Add LINSOLVE function.
 	* Restrict size of MUNIT to avoid thrashing the system.  [#625544]
 	* Fix text import crash.
+	* Add LEVERAGE function for regression tool.  [#691913]
 
 --------------------------------------------------------------------------
 Gnumeric 1.12.0
diff --git a/configure.ac b/configure.ac
index 1a71f85..29408c9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -146,7 +146,7 @@ PKG_PROG_PKG_CONFIG(0.18)
 
 dnl *****************************
 libspreadsheet_reqs="
-	libgoffice-${GOFFICE_API_VER}	>= 0.10.0
+	libgoffice-${GOFFICE_API_VER}	>= 0.10.1
 	libgsf-1		>= 1.14.24
 	libxml-2.0		>= 2.4.12
 "
diff --git a/plugins/fn-math/ChangeLog b/plugins/fn-math/ChangeLog
index b90fdf6..5c3df7f 100644
--- a/plugins/fn-math/ChangeLog
+++ b/plugins/fn-math/ChangeLog
@@ -1,3 +1,7 @@
+2013-01-17  Morten Welinder  <terra gnome org>
+
+	* functions.c (gnumeric_leverage): New function.
+
 2013-01-14  Morten Welinder  <terra gnome org>
 
 	* functions.c (gnumeric_munit): Restrict size to what would fit in
diff --git a/plugins/fn-math/functions.c b/plugins/fn-math/functions.c
index 2d0c24e..ad38ae1 100644
--- a/plugins/fn-math/functions.c
+++ b/plugins/fn-math/functions.c
@@ -2924,6 +2924,61 @@ gnumeric_mmult (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
 
 /***************************************************************************/
 
+static GnmFuncHelp const help_leverage[] = {
+        { GNM_FUNC_HELP_NAME, F_("LEVERAGE:calculate leverate")},
+        { GNM_FUNC_HELP_ARG, F_("A:a matrix")},
+	{ GNM_FUNC_HELP_DESCRIPTION,
+	  F_("Returns the diagonal of @{A} (@{A}^T @{A})^-1 @{A}T as a column vector.") },
+	{ GNM_FUNC_HELP_NOTE, F_("If the matrix is singular, #VALUE! is returned.") },
+        { GNM_FUNC_HELP_END}
+};
+
+
+static GnmValue *
+gnumeric_leverage (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
+{
+	GnmEvalPos const * const ep = ei->pos;
+	int rows, cols;
+	GORegressionResult regres;
+	gnm_float **A;
+	GnmStdError err;
+	GnmValue const *mat = argv[0];
+	gnm_float *x;
+	GnmValue *res;
+
+	if (validate_range_numeric_matrix (ep, mat, &rows, &cols, &err))
+		return value_new_error_std (ei->pos, err);
+
+	/* Guarantee shape and non-zero size */
+	if (!cols || !rows)
+		return value_new_error_VALUE (ei->pos);
+
+	A = value_to_matrix (mat, cols, rows, ep);
+	x = g_new (gnm_float, rows);
+	regres = gnm_linear_regression_leverage (A, x, rows, cols);
+	free_matrix (A, cols, rows);
+
+	if (regres != GO_REG_ok && regres != GO_REG_near_singular_good) {
+		res = value_new_error_VALUE (ei->pos);
+	} else {
+		int c, r;
+
+		res = value_new_array_non_init (1, rows);
+		for (c = 0; c < 1; c++) {
+			res->v_array.vals[c] = g_new (GnmValue *, rows);
+			for (r = 0; r < rows; r++)
+				res->v_array.vals[c][r] =
+					value_new_float (x[r]);
+		}
+	}
+
+	g_free (x);
+
+	return res;
+}
+
+/***************************************************************************/
+
 static GnmFuncHelp const help_linsolve[] = {
         { GNM_FUNC_HELP_NAME, F_("LINSOLVE:solve linear equation")},
         { GNM_FUNC_HELP_ARG, F_("mat:a matrix")},
@@ -3560,6 +3615,9 @@ GnmFuncDescriptor const math_functions[] = {
 	{ "minverse","A",      help_minverse,
 	  gnumeric_minverse, NULL, NULL, NULL,
 	  GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
+	{ "leverage", "A",  help_leverage,
+	  gnumeric_leverage, NULL, NULL, NULL,
+	  GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
 	{ "linsolve", "AA",  help_linsolve,
 	  gnumeric_linsolve, NULL, NULL, NULL,
 	  GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC, GNM_FUNC_TEST_STATUS_NO_TESTSUITE },
diff --git a/plugins/fn-math/plugin.xml.in b/plugins/fn-math/plugin.xml.in
index 457df3e..e266b6d 100644
--- a/plugins/fn-math/plugin.xml.in
+++ b/plugins/fn-math/plugin.xml.in
@@ -54,6 +54,7 @@
 				<function name="hypot"/>
 				<function name="int"/>
 				<function name="lcm"/>
+				<function name="leverage"/>
 				<function name="linsolve"/>
 				<function name="ln"/>
 				<function name="ln1p"/>
diff --git a/src/regression.h b/src/regression.h
index 1627b2c..d9a0c7b 100644
--- a/src/regression.h
+++ b/src/regression.h
@@ -12,6 +12,7 @@ G_BEGIN_DECLS
 #	define gnm_regression_stat_new go_regression_stat_newl
 #	define gnm_regression_stat_destroy go_regression_stat_destroyl
 #	define gnm_linear_regression go_linear_regressionl
+#	define gnm_linear_regression_leverage go_linear_regression_leveragel
 #	define gnm_exponential_regression go_exponential_regressionl
 #	define gnm_logarithmic_regression go_logarithmic_regressionl
 #	define gnm_logarithmic_fit go_logarithmic_fitl
@@ -25,6 +26,7 @@ G_BEGIN_DECLS
 #	define gnm_regression_stat_new go_regression_stat_new
 #	define gnm_regression_stat_destroy go_regression_stat_destroy
 #	define gnm_linear_regression go_linear_regression
+#	define gnm_linear_regression_leverage go_linear_regression_leverage
 #	define gnm_exponential_regression go_exponential_regression
 #	define gnm_logarithmic_regression go_logarithmic_regression
 #	define gnm_logarithmic_fit go_logarithmic_fit
diff --git a/src/tools/ChangeLog b/src/tools/ChangeLog
index 6389699..7ce79b6 100644
--- a/src/tools/ChangeLog
+++ b/src/tools/ChangeLog
@@ -1,3 +1,8 @@
+2013-01-17  Morten Welinder  <terra gnome org>
+
+	* analysis-tools.c (analysis_tool_regression_engine_run): Simplify
+	using new LEVERAGE function.
+
 2012-12-18  Morten Welinder <terra gnome org>
 
 	* Release 1.12.0
diff --git a/src/tools/analysis-tools.c b/src/tools/analysis-tools.c
index 5c469ee..16aae31 100644
--- a/src/tools/analysis-tools.c
+++ b/src/tools/analysis-tools.c
@@ -2881,8 +2881,7 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 	GnmFunc *fd_offset = NULL;
 	GnmFunc *fd_sumproduct = NULL;
 	GnmFunc *fd_mmult = NULL;
-	GnmFunc *fd_minverse = NULL;
-	GnmFunc *fd_munit = NULL;
+	GnmFunc *fd_leverage = NULL;
 	GnmFunc *fd_sumsq = NULL;
 
 	char const *str = ((info->group_by == GROUPED_BY_ROW) ? "row" : "col");
@@ -2898,8 +2897,7 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 	if (info->residual) {
 		fd_sumproduct  = analysis_tool_get_function ("SUMPRODUCT", dao);
 		fd_mmult  = analysis_tool_get_function ("MMULT", dao);
-		fd_minverse  = analysis_tool_get_function ("MINVERSE", dao);
-		fd_munit  = analysis_tool_get_function ("MUNIT", dao);
+		fd_leverage = analysis_tool_get_function ("LEVERAGE", dao);
 		fd_sumsq  = analysis_tool_get_function ("SUMSQ", dao);
 	}
 
@@ -3343,31 +3341,9 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 
 		if (dao_cell_is_visible (dao, xdim + 4, n_obs)) {
 			GnmExpr const *expr_X = dao_get_rangeref (dao, info->intercept ? 0 : 1, 1, xdim, n_obs);
-			GnmExpr const *expr_X_t =
-				gnm_expr_new_funcall1 (fd_transpose, gnm_expr_copy (expr_X));
-			GnmExpr const *expr_X_hat =
-				gnm_expr_new_funcall2
-				(fd_mmult,
-				 gnm_expr_new_funcall2
-				 (fd_mmult,
-				  expr_X,
-				  gnm_expr_new_funcall1
-				  (fd_minverse,
-				   gnm_expr_new_funcall2
-				   (fd_mmult,
-				    gnm_expr_copy (expr_X_t),
-				    gnm_expr_copy (expr_X)))),
-				 expr_X_t);
 			GnmExpr const *expr_diagonal =
-				gnm_expr_new_funcall2
-				(fd_mmult,
-				 gnm_expr_new_binary
-				 (expr_X_hat, GNM_EXPR_OP_MULT,
-				  gnm_expr_new_funcall1
-				  (fd_munit, gnm_expr_new_binary
-				   (dao_get_cellref (dao, 1, - 11 - xdim),
-				    GNM_EXPR_OP_ADD, gnm_expr_new_constant (value_new_int (1))))),
-				 dao_get_rangeref (dao, 0, 1, 0, n_obs));
+				gnm_expr_new_funcall1
+				(fd_leverage, expr_X);
 			GnmExpr const *expr_var =
 				gnm_expr_new_binary
 				(gnm_expr_new_funcall1
@@ -3463,10 +3439,8 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 		gnm_func_unref (fd_sumproduct);
 	if (fd_mmult != NULL)
 		gnm_func_unref (fd_mmult);
-	if (fd_minverse != NULL)
-		gnm_func_unref (fd_minverse);
-	if (fd_munit != NULL)
-		gnm_func_unref (fd_munit);
+	if (fd_leverage != NULL)
+		gnm_func_unref (fd_leverage);
 	if (fd_sumsq != NULL)
 		gnm_func_unref (fd_sumsq);
 



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