[gnumeric] Functions: Add LINSOLVE.



commit f80a1beb44f0124f57dff8cb00b6fcc12f550963
Author: Morten Welinder <terra gnome org>
Date:   Sun Jan 13 11:51:53 2013 -0500

    Functions: Add LINSOLVE.
    
    Without LINSOLVE, people get the idea that the inverse matrix can
    help them.  That really only works on a blackboard.

 NEWS                          |    1 +
 doc/C/func.defs               |   12 +++++-
 doc/C/functions.xml           |   39 ++++++++++++++++++-
 plugins/fn-math/ChangeLog     |    4 ++
 plugins/fn-math/functions.c   |   85 ++++++++++++++++++++++++++++++++++++++++-
 plugins/fn-math/plugin.xml.in |    1 +
 6 files changed, 139 insertions(+), 3 deletions(-)
---
diff --git a/NEWS b/NEWS
index 8fdbf9b..1f8cbfc 100644
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,7 @@ Morten:
 	* Fix multihead issue with clipboard.
 	* Improve EIGEN.   [#687926]
 	* Improve handling of unknown functions.  [#109442]
+	* Add LINSOLVE function.
 
 --------------------------------------------------------------------------
 Gnumeric 1.12.0
diff --git a/doc/C/func.defs b/doc/C/func.defs
index 1f94cee..c1877a0 100644
--- a/doc/C/func.defs
+++ b/doc/C/func.defs
@@ -3419,6 +3419,16 @@ The depreciation coefficient used is:
 @SEEALSO=GCD
 
 @CATEGORY=Mathematics
+ FUNCTION=LINSOLVE
+ SHORTDESC=solve linear equation
+ SYNTAX=LINSOLVE(mat,col)
+ ARGUMENTDESCRIPTION=@{mat}: a matrix
+ {col}: a column
+ DESCRIPTION=Solves the equation @{mat}*x= {col} and returns x.
+ NOTE=If the matrix is singular, #VALUE! is returned.
+ SEEALSO=MINVERSE
+
+ CATEGORY=Mathematics
 @FUNCTION=LN
 @SHORTDESC=the natural logarithm of @{x}
 @SYNTAX=LN(x)
@@ -3478,7 +3488,7 @@ The depreciation coefficient used is:
 @ARGUMENTDESCRIPTION= {matrix}: a square matrix
 @NOTE=If @{matrix} is not invertible, MINVERSE returns #NUM! If @{matrix} does not contain an equal number of columns and rows, MINVERSE returns #VALUE!
 @EXCEL=This function is Excel compatible.
- SEEALSO=MMULT,MDETERM
+ SEEALSO=MMULT,MDETERM,LINSOLVE
 
 @CATEGORY=Mathematics
 @FUNCTION=MMULT
diff --git a/doc/C/functions.xml b/doc/C/functions.xml
index 0599684..4d546f6 100644
--- a/doc/C/functions.xml
+++ b/doc/C/functions.xml
@@ -11521,6 +11521,42 @@
       </para>
       </refsect1>
     </refentry>
+    <refentry id="gnumeric-function-LINSOLVE">
+      <refmeta>
+        <refentrytitle>
+          <function>LINSOLVE</function>
+        </refentrytitle>
+      </refmeta>
+      <refnamediv>
+        <refname>
+          <function>LINSOLVE</function>
+        </refname>
+        <refpurpose>
+        solve linear equation
+      </refpurpose>
+      </refnamediv>
+      <refsynopsisdiv>
+        <synopsis><function>LINSOLVE</function>(<parameter>mat</parameter>,<parameter>col</parameter>)</synopsis>
+      </refsynopsisdiv>
+      <refsect1>
+        <title>Arguments</title>
+        <para><parameter>mat</parameter>: a matrix</para>
+        <para><parameter>col</parameter>: a column</para>
+      </refsect1>
+      <refsect1>
+        <title>Description</title>
+        <para>Solves the equation <parameter>mat</parameter>*x=<parameter>col</parameter> and returns x.</para>
+      </refsect1>
+      <refsect1>
+        <title>Note</title>
+        <para>If the matrix is singular, #VALUE! is returned.</para>
+      </refsect1>
+      <refsect1>
+        <title>See also</title>
+        <para><link linkend="gnumeric-function-MINVERSE"><function>MINVERSE</function></link>.
+      </para>
+      </refsect1>
+    </refentry>
     <refentry id="gnumeric-function-LN">
       <refmeta>
         <refentrytitle>
@@ -11767,7 +11803,8 @@
       <refsect1>
         <title>See also</title>
         <para><link linkend="gnumeric-function-MMULT"><function>MMULT</function></link>,
-        <link linkend="gnumeric-function-MDETERM"><function>MDETERM</function></link>.
+        <link linkend="gnumeric-function-MDETERM"><function>MDETERM</function></link>,
+        <link linkend="gnumeric-function-LINSOLVE"><function>LINSOLVE</function></link>.
       </para>
       </refsect1>
     </refentry>
diff --git a/plugins/fn-math/ChangeLog b/plugins/fn-math/ChangeLog
index 3211a08..bf68185 100644
--- a/plugins/fn-math/ChangeLog
+++ b/plugins/fn-math/ChangeLog
@@ -1,3 +1,7 @@
+2013-01-13  Morten Welinder  <terra gnome org>
+
+	* functions.c (gnumeric_linsolve): New function.
+
 2012-12-18  Morten Welinder <terra gnome org>
 
 	* Release 1.12.0
diff --git a/plugins/fn-math/functions.c b/plugins/fn-math/functions.c
index 5ec7813..9de078c 100644
--- a/plugins/fn-math/functions.c
+++ b/plugins/fn-math/functions.c
@@ -2588,7 +2588,7 @@ static GnmFuncHelp const help_minverse[] = {
 	{ GNM_FUNC_HELP_NOTE, F_("If @{matrix} is not invertible, MINVERSE returns #NUM!") },
 	{ GNM_FUNC_HELP_NOTE, F_("If @{matrix} does not contain an equal number of columns and rows, MINVERSE returns #VALUE!") },
 	{ GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
-	{ GNM_FUNC_HELP_SEEALSO, "MMULT,MDETERM"},
+	{ GNM_FUNC_HELP_SEEALSO, "MMULT,MDETERM,LINSOLVE"},
         { GNM_FUNC_HELP_END}
 };
 
@@ -2664,6 +2664,22 @@ value_to_matrix (GnmValue const *v, int cols, int rows, GnmEvalPos const *ep)
 	return res;
 }
 
+static gnm_float **
+value_to_tmatrix (GnmValue const *v, int cols, int rows, GnmEvalPos const *ep)
+{
+	gnm_float **res = g_new (gnm_float *, cols);
+	int r, c;
+
+	for (c = 0; c < cols; c++) {
+		res[c] = g_new (gnm_float, rows);
+		for (r = 0; r < rows; r++)
+		        res[c][r] =
+				value_get_as_float (value_area_get_x_y (v, c, r, ep));
+	}
+
+	return res;
+}
+
 static void
 free_matrix (gnm_float **mat, G_GNUC_UNUSED int cols, int rows)
 {
@@ -2907,6 +2923,70 @@ gnumeric_mmult (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
 
 /***************************************************************************/
 
+static GnmFuncHelp const help_linsolve[] = {
+        { GNM_FUNC_HELP_NAME, F_("LINSOLVE:solve linear equation")},
+        { GNM_FUNC_HELP_ARG, F_("mat:a matrix")},
+        { GNM_FUNC_HELP_ARG, F_("col:a column")},
+	{ GNM_FUNC_HELP_DESCRIPTION,
+	  F_("Solves the equation @{mat}*x= {col} and returns x.") },
+	{ GNM_FUNC_HELP_NOTE, F_("If the matrix is singular, #VALUE! is returned.") },
+	{ GNM_FUNC_HELP_SEEALSO, "MINVERSE"},
+        { GNM_FUNC_HELP_END}
+};
+
+
+static GnmValue *
+gnumeric_linsolve (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
+{
+	GnmEvalPos const * const ep = ei->pos;
+	int mrows, mcols, crows, ccols;
+	GORegressionResult regres;
+	gnm_float **A;
+	gnm_float **b;
+	GnmStdError err;
+	GnmValue const *mat = argv[0];
+	GnmValue const *col = argv[1];
+	gnm_float *x;
+	GnmValue *res;
+
+	if (validate_range_numeric_matrix (ep, mat, &mrows, &mcols, &err))
+		return value_new_error_std (ei->pos, err);
+
+	if (validate_range_numeric_matrix (ep, col, &crows, &ccols, &err))
+		return value_new_error_std (ei->pos, err);
+
+	/* Guarantee shape and non-zero size */
+	if (mrows != mcols || mrows != crows || ccols != 1 || !mcols)
+		return value_new_error_VALUE (ei->pos);
+
+	A = value_to_matrix (mat, mcols, mrows, ep);
+	b = value_to_tmatrix (col, ccols, crows, ep);
+	x = g_new (gnm_float, crows);
+	regres = gnm_linear_solve (A, b[0], crows, x);
+	free_matrix (A, mcols, mrows);
+	free_matrix (b, crows, ccols); /* tmatrix */
+
+	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 (ccols, crows);
+		for (c = 0; c < ccols; c++) {
+			res->v_array.vals[c] = g_new (GnmValue *, crows);
+			for (r = 0; r < crows; r++)
+				res->v_array.vals[c][r] =
+					value_new_float (x[r]);
+		}
+	}
+
+	g_free (x);
+
+	return res;
+}
+
+/***************************************************************************/
+
 static GnmFuncHelp const help_mdeterm[] = {
         { GNM_FUNC_HELP_NAME, F_("MDETERM:the determinant of the matrix @{matrix}")},
         { GNM_FUNC_HELP_ARG, F_("matrix:a square matrix")},
@@ -3479,6 +3559,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 },
+	{ "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 },
 	{ "mdeterm", "A",  help_mdeterm,
 	  gnumeric_mdeterm, NULL, NULL, NULL,
 	  GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
diff --git a/plugins/fn-math/plugin.xml.in b/plugins/fn-math/plugin.xml.in
index c27aef3..457df3e 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="linsolve"/>
 				<function name="ln"/>
 				<function name="ln1p"/>
 				<function name="log"/>



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