[gnumeric] Add HPFILTER function calculating the Hodrick Prescott Filter.



commit 0a873b87a4dbe57c64871a8ee9f3b871f02127e7
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date:   Fri Aug 19 13:05:00 2011 -0600

    Add HPFILTER function calculating the Hodrick Prescott Filter.
    
    2011-08-19 Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* plugin.xml.in: add hpfilter
    	* functions.c (help_fourier): use the correct error in teh description
    	(help_hpfilter): new
    	(gnm_hpfilter): new
    	(gnumeric_hpfilter): new
    	(TimeSeriesAnalysis_functions): add hpfilter
    
    2011-08-19 Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* src/workbook-view.c (wb_view_auto_expr_recalc): chaeck for NULL
    	attribute list
    
    2011-08-19  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* func.defs: update
    	* functions.xml: update

 ChangeLog                    |    5 +
 NEWS                         |    1 +
 doc/C/ChangeLog              |    5 +
 doc/C/func.defs              |   12 +++-
 doc/C/functions.xml          |   34 ++++++++-
 plugins/fn-tsa/ChangeLog     |    9 ++
 plugins/fn-tsa/functions.c   |  170 ++++++++++++++++++++++++++++++++++++++++-
 plugins/fn-tsa/plugin.xml.in |    1 +
 src/workbook-view.c          |   12 ++-
 9 files changed, 237 insertions(+), 12 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index cd91306..0011c3c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2011-08-19 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* src/workbook-view.c (wb_view_auto_expr_recalc): chaeck for NULL
+	attribute list
+
 2011-08-18 Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* src/consolidate.c: add argument to tools engine
diff --git a/NEWS b/NEWS
index c8f81c2..8a06030 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Andreas:
 	* Fix writing of scatter style in xlsx export. [#656799]
 	* Provide progress feedback for xlsx import. [#634803]
 	* Provide progress feedback when generating random numbers.
+	* Add HPFILTER function calculating the Hodrick Prescott Filter.
 
 Jean:
 	* Make things build against gtk+-3.0.
diff --git a/doc/C/ChangeLog b/doc/C/ChangeLog
index 9cd67d4..a2b741c 100644
--- a/doc/C/ChangeLog
+++ b/doc/C/ChangeLog
@@ -1,3 +1,8 @@
+2011-08-19  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* func.defs: update
+	* functions.xml: update
+
 2011-08-15  Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* func.defs: update
diff --git a/doc/C/func.defs b/doc/C/func.defs
index 9155f09..088fa3b 100644
--- a/doc/C/func.defs
+++ b/doc/C/func.defs
@@ -6133,7 +6133,17 @@ The distinction between half-width and full-width characters is described in htt
 @DESCRIPTION=This array function returns the Fourier or inverse Fourier transform of the given data sequence.
 The output consists of one column of complex numbers if @{Separate} is false and of two columns of real numbers if @{Separate} is true.
 If @{Separate} is true the first output column contains the real parts and the second column the imaginary parts.
- NOTE=If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #NUM!
+ NOTE=If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #VALUE!
+
+ CATEGORY=Time Series Analysis
+ FUNCTION=HPFILTER
+ SHORTDESC=Hodrick Prescott Filter
+ SYNTAX=HPFILTER(Sequence,Î)
+ ARGUMENTDESCRIPTION=@{Sequence}: the data sequence to be transformed
+ {Î}: filter parameter Î, defaults to 1600
+ DESCRIPTION=This array function returns the trend and cyclical components obtained by applying the Hodrick Prescott Filter with parameter @{Î} to the given data sequence.
+The output consists of two columns of numbers, the first containing the trend component, the second the cyclical component.
+ NOTE=If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #VALUE! If @{Sequence} contians less than 6 numerical values, this function returns #VALUE!
 
 @CATEGORY=Time Series Analysis
 @FUNCTION=INTERPOLATION
diff --git a/doc/C/functions.xml b/doc/C/functions.xml
index ed8697c..83fadd9 100644
--- a/doc/C/functions.xml
+++ b/doc/C/functions.xml
@@ -21126,7 +21126,39 @@
       </refsect1>
       <refsect1>
         <title>Note</title>
-        <para>If <parameter>Sequence</parameter> is neither an n by 1 nor 1 by n array, this function returns #NUM!</para>
+        <para>If <parameter>Sequence</parameter> is neither an n by 1 nor 1 by n array, this function returns #VALUE!</para>
+      </refsect1>
+    </refentry>
+    <refentry id="gnumeric-function-HPFILTER">
+      <refmeta>
+        <refentrytitle>
+          <function>HPFILTER</function>
+        </refentrytitle>
+      </refmeta>
+      <refnamediv>
+        <refname>
+          <function>HPFILTER</function>
+        </refname>
+        <refpurpose>
+        Hodrick Prescott Filter
+      </refpurpose>
+      </refnamediv>
+      <refsynopsisdiv>
+        <synopsis><function>HPFILTER</function>(<parameter>Sequence</parameter>,<parameter/>Î)</synopsis>
+      </refsynopsisdiv>
+      <refsect1>
+        <title>Arguments</title>
+        <para><parameter>Sequence</parameter>: the data sequence to be transformed</para>
+        <para><parameter>Î</parameter>: filter parameter Î, defaults to 1600</para>
+      </refsect1>
+      <refsect1>
+        <title>Description</title>
+        <para>This array function returns the trend and cyclical components obtained by applying the Hodrick Prescott Filter with parameter <parameter>Î</parameter> to the given data sequence.</para>
+        <para>The output consists of two columns of numbers, the first containing the trend component, the second the cyclical component.</para>
+      </refsect1>
+      <refsect1>
+        <title>Note</title>
+        <para>If <parameter>Sequence</parameter> is neither an n by 1 nor 1 by n array, this function returns #VALUE! If <parameter>Sequence</parameter> contians less than 6 numerical values, this function returns #VALUE!</para>
       </refsect1>
     </refentry>
     <refentry id="gnumeric-function-INTERPOLATION">
diff --git a/plugins/fn-tsa/ChangeLog b/plugins/fn-tsa/ChangeLog
index 034c36c..501b8eb 100644
--- a/plugins/fn-tsa/ChangeLog
+++ b/plugins/fn-tsa/ChangeLog
@@ -1,3 +1,12 @@
+2011-08-19 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* plugin.xml.in: add hpfilter
+	* functions.c (help_fourier): use the correct error in teh description
+	(help_hpfilter): new
+	(gnm_hpfilter): new
+	(gnumeric_hpfilter): new
+	(TimeSeriesAnalysis_functions): add hpfilter
+
 2011-07-31  Morten Welinder <terra gnome org>
 
 	* Release 1.10.17
diff --git a/plugins/fn-tsa/functions.c b/plugins/fn-tsa/functions.c
index 6d841f0..ed881bb 100644
--- a/plugins/fn-tsa/functions.c
+++ b/plugins/fn-tsa/functions.c
@@ -384,7 +384,7 @@ static GnmFuncHelp const help_interpolation[] = {
 	{ GNM_FUNC_HELP_NOTE, F_("Strings and empty cells in @{abscissae} and @{ordinates} are ignored.") },
 	{ GNM_FUNC_HELP_NOTE, F_("If several target data are provided they must be in the same column in consecutive cells.") },
 	{ GNM_FUNC_HELP_SEEALSO, "PERIODOGRAM" },
-	{ GNM_FUNC_HELP_END }
+	{ GNM_FUNC_HELP_END, NULL }
 };
 
 static GnmValue *
@@ -538,7 +538,7 @@ static GnmFuncHelp const help_periodogram[] = {
 	{ GNM_FUNC_HELP_NOTE, F_("Strings and empty cells in @{abscissae} and @{ordinates} are ignored.") },
 	{ GNM_FUNC_HELP_NOTE, F_("If several target data are provided they must be in the same column in consecutive cells.") },
 	{ GNM_FUNC_HELP_SEEALSO, "INTERPOLATION" },
-	{ GNM_FUNC_HELP_END }
+	{ GNM_FUNC_HELP_END, NULL }
 };
 
 static GnmValue *
@@ -787,8 +787,8 @@ static GnmFuncHelp const help_fourier[] = {
 	{ GNM_FUNC_HELP_DESCRIPTION, F_("This array function returns the Fourier or inverse Fourier transform of the given data sequence.") },
 	{ GNM_FUNC_HELP_DESCRIPTION, F_("The output consists of one column of complex numbers if @{Separate} is false and of two columns of real numbers if @{Separate} is true.") },
 { GNM_FUNC_HELP_DESCRIPTION, F_("If @{Separate} is true the first output column contains the real parts and the second column the imaginary parts.") },
-	{ GNM_FUNC_HELP_NOTE, F_("If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #NUM!") },
-	{ GNM_FUNC_HELP_END }
+	{ GNM_FUNC_HELP_NOTE, F_("If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #VALUE!") },
+	{ GNM_FUNC_HELP_END, NULL }
 };
 
 static GnmValue *
@@ -876,6 +876,162 @@ gnumeric_fourier (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
 	return res;
 }
 
+/******************************************************************************/
+
+static GnmFuncHelp const help_hpfilter[] = {
+	{ GNM_FUNC_HELP_NAME, F_("HPFILTER:Hodrick Prescott Filter") },
+	{ GNM_FUNC_HELP_ARG, F_("Sequence:the data sequence to be transformed") },
+	{ GNM_FUNC_HELP_ARG, F_("\316\273:filter parameter \316\273, defaults to 1600") },
+	{ GNM_FUNC_HELP_DESCRIPTION, F_("This array function returns the trend and cyclical components obtained by applying the Hodrick Prescott Filter with parameter @{\316\273} to the given data sequence.") },
+	{ GNM_FUNC_HELP_DESCRIPTION, F_("The output consists of two columns of numbers, the first containing the trend component, the second the cyclical component.") },
+	{ GNM_FUNC_HELP_NOTE, F_("If @{Sequence} is neither an n by 1 nor 1 by n array, this function returns #VALUE!") },
+	{ GNM_FUNC_HELP_NOTE, F_("If @{Sequence} contians less than 6 numerical values, this function returns #VALUE!") },
+	{ GNM_FUNC_HELP_END, NULL }
+};
+
+
+static void
+gnm_hpfilter (gnm_float *data, int n, gnm_float lambda, int *err)
+{
+ 	gnm_float *a, *b, *c;
+ 	int i;
+ 	gnm_float lambda6 = 6 * lambda + 1;
+ 	gnm_float lambda4 = -4 * lambda;
+ 	gnm_float h[5] = {0,0,0,0,0};
+ 	gnm_float g[5] = {0,0,0,0,0};
+ 	gnm_float j[2] = {0,0};
+ 	gnm_float h_b, h_c, denom;
+
+ 	g_return_if_fail (n > 5);
+ 	g_return_if_fail (data != NULL);
+ 	g_return_if_fail (err != NULL);
+
+ 	/* Initializing arrays a, b, and c */
+
+ 	a = g_new (gnm_float, n);
+ 	b = g_new (gnm_float, n);
+ 	c = g_new (gnm_float, n);
+
+ 	a[0] = lambda + 1;
+ 	b[0] = -2 * lambda;
+ 	c[0] = lambda;
+
+ 	for (i = 1; i < n - 2; i++) {
+ 		a[i] = lambda6;
+ 		b[i] = lambda4;
+ 		c[i] = lambda;
+ 	}
+
+ 	a[n - 2] = a[1] = lambda6 - lambda;
+ 	a[n - 1] = a[0];
+ 	b[n - 2] = b[0];
+ 	b[n - 1] = 0;
+ 	c[n - 2] = 0;
+ 	c[n - 1] = 0;
+	
+ 	/* Forward */
+ 	for (i = 0; i < n; i++) {
+ 		denom = a[i]- h[3]*h[0] - g[4]*g[1];
+ 		if (denom == 0) {
+ 			*err = GNM_ERROR_DIV0;
+ 			goto done;
+ 		}
+
+ 		h_b = b[i];
+ 		g[0] = h[0];
+ 		b[i] = h[0] = (h_b - h[3] * h[1])/denom;
+
+ 		h_c = c[i];
+ 		g[1] = h[1];
+ 		c[i] = h[1] = h_c/denom;
+
+ 		a[i] = (data[i] - g[2]*g[4] - h[2]*h[3])/denom;
+
+ 		g[2] = h[2];
+ 		h[2] = a[i];
+ 		h[3] = h_b - h[4] * g[0];
+ 		g[4] = h[4];
+ 		h[4] = h_c;
+ 	}
+
+ 	data[n - 1] = j[0] = a[n - 1];
+
+ 	/* Backwards */
+ 	for (i = n - 1; i > 0; i--) {
+ 		data[i - 1] = a[i - 1] - b[i - 1] * j[0] - c[i - 1] * j[1];
+ 		j[1] = j[0];
+ 		j[0] = data[i - 1];
+ 	}
+
+ done:
+ 	g_free (a);
+ 	g_free (b);
+ 	g_free (c);
+ 	return;
+}
+
+static GnmValue *
+gnumeric_hpfilter (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
+{
+	gnm_float *raw, *filtered;
+	gnm_float lambda;
+	int n = 0;
+	GnmValue *error = NULL;
+	GnmValue *res;
+	CollectFlags flags;
+	GnmEvalPos const * const ep = ei->pos;
+	GnmValue const * const Pt = argv[0];
+	int i, err = -1;
+
+	int const cols = value_area_get_width (Pt, ep);
+	int const rows = value_area_get_height (Pt, ep);
+
+	if (cols != 1 && rows != 1) {
+		res = value_new_error_std (ei->pos, GNM_ERROR_VALUE);
+		return res;
+	}
+
+	flags=COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS;
+
+	raw = collect_floats_value (argv[0], ei->pos, flags,
+					      &n, &error);
+	if (error)
+		return error;
+
+	if (n < 6) {
+		g_free (raw);
+		res = value_new_error_std (ei->pos, GNM_ERROR_VALUE);
+		return res;
+	}
+
+	if (argv[1])
+		lambda = value_get_as_float (argv[1]);
+	else
+		lambda = 1600.;
+
+
+	/* Filter and return the result */
+	filtered = g_new0 (gnm_float, n);
+	for (i = 0; i < n; i++)
+		filtered[i] = raw[i];
+	gnm_hpfilter (filtered, n, lambda, &err);
+	if (err > -1) {
+		g_free (raw);
+		g_free (filtered);
+		res = value_new_error_std (ei->pos, err);
+		return res;
+	}
+
+	res = value_new_array_empty (2 , n);
+	for (i = 0; i < n; i++) {
+		res->v_array.vals[0][i] = value_new_float (filtered[i]);
+		res->v_array.vals[1][i] = value_new_float (raw[i] - filtered[i]);
+	}
+	g_free (raw);
+	g_free (filtered);
+
+	return res;
+}
 
 const GnmFuncDescriptor TimeSeriesAnalysis_functions[] = {
 
@@ -891,5 +1047,9 @@ const GnmFuncDescriptor TimeSeriesAnalysis_functions[] = {
 	  help_fourier, gnumeric_fourier, NULL, NULL, NULL, NULL,
 	  GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
 
-        {NULL}
+	{ "hpfilter",       "A|fb",
+	  help_hpfilter, gnumeric_hpfilter, NULL, NULL, NULL, NULL,
+	  GNM_FUNC_RETURNS_NON_SCALAR, GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
+
+	{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0}
 };
diff --git a/plugins/fn-tsa/plugin.xml.in b/plugins/fn-tsa/plugin.xml.in
index 36ebf54..a5aad67 100644
--- a/plugins/fn-tsa/plugin.xml.in
+++ b/plugins/fn-tsa/plugin.xml.in
@@ -15,6 +15,7 @@
             			<function name="interpolation"/>
             			<function name="periodogram"/>
             			<function name="fourier"/>
+            			<function name="hpfilter"/>
 			</functions>
 		</service>
 	</services>
diff --git a/src/workbook-view.c b/src/workbook-view.c
index 8c5bb0c..0589650 100644
--- a/src/workbook-view.c
+++ b/src/workbook-view.c
@@ -545,11 +545,13 @@ wb_view_auto_expr_recalc (WorkbookView *wbv)
 				g_string_append (str, pango_layout_get_text (layout));
 				/* We need to shift the attribute list  */
 				atl = pango_attr_list_ref (pango_layout_get_attributes (layout));
-				attrs = pango_attr_list_new ();
-				pango_attr_list_splice
-					(attrs, atl, old_len,
-					 str->len - old_len);
-				pango_attr_list_unref (atl);
+				if (atl != NULL) {
+					attrs = pango_attr_list_new ();
+					pango_attr_list_splice
+						(attrs, atl, old_len,
+						 str->len - old_len);
+					pango_attr_list_unref (atl);
+				}
 			} else
 				g_string_append (str,  "Internal ERROR!");
 			g_object_unref (layout);



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