[gnumeric] Derivative: use a GnmFunc signal instead of ad-hoc handlers.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] Derivative: use a GnmFunc signal instead of ad-hoc handlers.
- Date: Sun, 27 May 2018 02:56:19 +0000 (UTC)
commit 03f01e3833a5ba3e4839a34c45a787de1af3bfc5
Author: Morten Welinder <terra gnome org>
Date: Sat May 26 22:55:29 2018 -0400
Derivative: use a GnmFunc signal instead of ad-hoc handlers.
plugins/fn-math/functions.c | 40 +++++++--------
src/expr-deriv.c | 119 +++++++++++++++-----------------------------
src/expr-deriv.h | 24 +++------
src/func-builtin.c | 20 +++-----
src/func.c | 67 ++++++++++++++++++++++++-
src/func.h | 7 +++
src/gnm-marshalers.list | 1 +
src/gnumeric-fwd.h | 1 +
8 files changed, 146 insertions(+), 133 deletions(-)
---
diff --git a/plugins/fn-math/functions.c b/plugins/fn-math/functions.c
index 333dfb089..4963c7f53 100644
--- a/plugins/fn-math/functions.c
+++ b/plugins/fn-math/functions.c
@@ -968,10 +968,10 @@ gnumeric_exp (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
}
static GnmExpr const *
-gnumeric_exp_deriv (GnmExpr const *expr, GnmEvalPos const *ep,
- GnmExprDeriv *info, gpointer data)
+gnumeric_exp_deriv (GnmFunc *func, GnmExpr const *expr, GnmEvalPos const *ep,
+ GnmExprDeriv *info)
{
- return gnm_expr_copy (expr);
+ return gnm_expr_deriv_chain (expr, gnm_expr_copy (expr), ep, info);
}
/***************************************************************************/
@@ -1318,9 +1318,11 @@ static GnmExpr const *
gnumeric_ln_deriv (GnmExpr const *expr, GnmEvalPos const *ep,
GnmExprDeriv *info, gpointer data)
{
- return gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)),
- GNM_EXPR_OP_DIV,
- gnm_expr_copy (gnm_expr_get_func_arg (expr, 0)));
+ GnmExpr const *deriv =
+ gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)),
+ GNM_EXPR_OP_DIV,
+ gnm_expr_copy (gnm_expr_get_func_arg (expr, 0)));
+ return gnm_expr_deriv_chain (expr, deriv, ep, info);
}
/***************************************************************************/
@@ -1750,8 +1752,9 @@ gnumeric_sumsq (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
}
static GnmExpr const *
-gnumeric_sumsq_deriv (GnmExpr const *expr, GnmEvalPos const *ep,
- GnmExprDeriv *info, gpointer data)
+gnumeric_sumsq_deriv (GnmFunc *func,
+ GnmExpr const *expr, GnmEvalPos const *ep,
+ GnmExprDeriv *info)
{
GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info);
GnmExpr const *res;
@@ -3742,24 +3745,15 @@ GnmFuncDescriptor const math_functions[] = {
G_MODULE_EXPORT void
go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
{
- gnm_expr_deriv_install_handler (gnm_func_lookup ("sumsq", NULL),
- gnumeric_sumsq_deriv,
- GNM_EXPR_DERIV_NO_CHAIN | GNM_EXPR_DERIV_OPTIMIZE,
- NULL, NULL);
- gnm_expr_deriv_install_handler (gnm_func_lookup ("exp", NULL),
- gnumeric_exp_deriv,
- GNM_EXPR_DERIV_CHAIN,
- NULL, NULL);
- gnm_expr_deriv_install_handler (gnm_func_lookup ("ln", NULL),
- gnumeric_ln_deriv,
- GNM_EXPR_DERIV_CHAIN,
- NULL, NULL);
+ g_signal_connect (gnm_func_lookup ("sumsq", NULL),
+ "derivative", G_CALLBACK (gnumeric_sumsq_deriv), NULL);
+ g_signal_connect (gnm_func_lookup ("exp", NULL),
+ "derivative", G_CALLBACK (gnumeric_exp_deriv), NULL);
+ g_signal_connect (gnm_func_lookup ("ln", NULL),
+ "derivative", G_CALLBACK (gnumeric_ln_deriv), NULL);
}
G_MODULE_EXPORT void
go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc)
{
- gnm_expr_deriv_uninstall_handler (gnm_func_lookup ("sumsq", NULL));
- gnm_expr_deriv_uninstall_handler (gnm_func_lookup ("exp", NULL));
- gnm_expr_deriv_uninstall_handler (gnm_func_lookup ("ln", NULL));
}
diff --git a/src/expr-deriv.c b/src/expr-deriv.c
index 347496bdc..981ccbed5 100644
--- a/src/expr-deriv.c
+++ b/src/expr-deriv.c
@@ -32,25 +32,6 @@
/* ------------------------------------------------------------------------- */
-static GHashTable *deriv_handlers;
-
-struct DerivHandler {
- GnmExprDerivHandler handler;
- GnmExprDerivFlags flags;
- gpointer data;
- GDestroyNotify notify;
-};
-
-static void
-deriv_handler_free (struct DerivHandler *di)
-{
- if (di->notify)
- di->notify (di->data);
- g_free (di);
-}
-
-/* ------------------------------------------------------------------------- */
-
struct GnmExprDeriv_ {
unsigned ref_count;
GnmEvalPos var;
@@ -474,7 +455,7 @@ gnm_expr_deriv_collect (GnmExpr const *expr,
&user);
}
- return user.args;
+ return g_slist_reverse (user.args);
}
/* ------------------------------------------------------------------------- */
@@ -494,7 +475,15 @@ gnm_expr_deriv_collect (GnmExpr const *expr,
#define COMMON_BINARY_END }
-
+/**
+ * gnm_expr_deriv:
+ * @expr: #GnmExpr
+ * @ep: position for @expr
+ * @info: Derivative information
+ *
+ * Returns: (transfer full) (nullable): the derivative of @expr with respect
+ * to @info.
+ */
GnmExpr const *
gnm_expr_deriv (GnmExpr const *expr,
GnmEvalPos const *ep,
@@ -585,33 +574,12 @@ gnm_expr_deriv (GnmExpr const *expr,
case GNM_EXPR_OP_FUNCALL: {
GnmFunc *f = gnm_expr_get_func_def (expr);
- struct DerivHandler const *di = deriv_handlers
- ? g_hash_table_lookup (deriv_handlers, f)
- : NULL;
- GnmExpr const *res = di
- ? di->handler (expr, ep, info, di->data)
- : NULL;
- if (!res)
- return NULL;
-
- if (di->flags & GNM_EXPR_DERIV_CHAIN) {
- GnmExpr const *e2 =
- gnm_expr_deriv (gnm_expr_get_func_arg (expr, 0), ep, info);
- if (!e2) {
- gnm_expr_free (res);
- return NULL;
- }
- res = mmul (res, 0, e2, 0);
+ GnmExpr const *res = gnm_func_derivative (f, expr, ep, info);
+ GnmExpr const *opt = optimize (res);
+ if (opt) {
+ gnm_expr_free (res);
+ res = opt;
}
-
- if (di->flags & GNM_EXPR_DERIV_OPTIMIZE) {
- GnmExpr const *opt = optimize (res);
- if (opt) {
- gnm_expr_free (res);
- res = opt;
- }
- }
-
return res;
}
@@ -794,40 +762,35 @@ gnm_expr_cell_deriv_value (GnmCell *y, GnmCell *x)
/* ------------------------------------------------------------------------- */
/**
- * gnm_expr_deriv_install_handler:
- * @func: the function being given a handler
- * @h: (scope notified): #GnmExprDerivHandler
- * @flags:
- * @data: user data for @h
- * @notify: destroy notification for @data
+ * gnm_expr_deriv_chain:
+ * @expr: #GnmExpr for a function call with one argument
+ * @deriv: (transfer full) (nullable): Derivative of @expr's function.
+ * @ep: position for @expr
+ * @info: Derivative information
+ *
+ * Applies the chain rule to @expr.
+ *
+ * Returns: (transfer full) (nullable): the derivative of @expr with respect
+ * to @info.
*/
-void
-gnm_expr_deriv_install_handler (GnmFunc *func, GnmExprDerivHandler h,
- GnmExprDerivFlags flags,
- gpointer data,
- GDestroyNotify notify)
+GnmExpr const *
+gnm_expr_deriv_chain (GnmExpr const *expr,
+ GnmExpr const *deriv,
+ GnmEvalPos const *ep,
+ GnmExprDeriv *info)
{
- struct DerivHandler *hdata;
-
- if (!deriv_handlers) {
- deriv_handlers = g_hash_table_new_full
- (g_direct_hash, g_direct_equal,
- NULL, (GDestroyNotify)deriv_handler_free);
- }
+ GnmExpr const *deriv2;
- hdata = g_new (struct DerivHandler, 1);
- hdata->handler = h;
- hdata->flags = flags;
- hdata->data = data;
- hdata->notify = notify;
+ if (!deriv)
+ return NULL;
- g_hash_table_replace (deriv_handlers, func, hdata);
-}
+ deriv2 = gnm_expr_deriv (gnm_expr_get_func_arg (expr, 0), ep, info);
+ if (!deriv2) {
+ gnm_expr_free (deriv);
+ return NULL;
+ }
-void
-gnm_expr_deriv_uninstall_handler (GnmFunc *func)
-{
- g_hash_table_remove (deriv_handlers, func);
+ return mmul (deriv, 0, deriv2, 0);
}
/* ------------------------------------------------------------------------- */
@@ -835,10 +798,6 @@ gnm_expr_deriv_uninstall_handler (GnmFunc *func)
void
_gnm_expr_deriv_shutdown (void)
{
- if (deriv_handlers) {
- g_hash_table_destroy (deriv_handlers);
- deriv_handlers = NULL;
- }
}
/* ------------------------------------------------------------------------- */
diff --git a/src/expr-deriv.h b/src/expr-deriv.h
index 0b9c0c9e6..5e30826a8 100644
--- a/src/expr-deriv.h
+++ b/src/expr-deriv.h
@@ -3,13 +3,12 @@
G_BEGIN_DECLS
+#include <gnumeric-fwd.h>
#include <expr.h>
#include <numbers.h>
/* ------------------------------------------------------------------------- */
-typedef struct GnmExprDeriv_ GnmExprDeriv;
-
GType gnm_expr_deriv_info_get_type (void);
GnmExprDeriv *gnm_expr_deriv_info_new (void);
@@ -33,26 +32,17 @@ GnmExprTop const *gnm_expr_cell_deriv (GnmCell *y, GnmCell *x);
gnm_float gnm_expr_cell_deriv_value (GnmCell *y, GnmCell *x);
-/* ------------------------------------------------------------------------- */
+GnmExpr const *gnm_expr_deriv_chain (GnmExpr const *expr,
+ GnmExpr const *deriv,
+ GnmEvalPos const *ep,
+ GnmExprDeriv *info);
GnmExprList *gnm_expr_deriv_collect (GnmExpr const *expr,
GnmEvalPos const *ep,
GnmExprDeriv *info);
-typedef GnmExpr const * (*GnmExprDerivHandler) (GnmExpr const *expr,
- GnmEvalPos const *ep,
- GnmExprDeriv *info,
- gpointer user);
-typedef enum {
- GNM_EXPR_DERIV_NO_CHAIN = 0x0,
- GNM_EXPR_DERIV_CHAIN = 0x1,
- GNM_EXPR_DERIV_OPTIMIZE = 0x2
-} GnmExprDerivFlags;
-
-void gnm_expr_deriv_install_handler (GnmFunc *func, GnmExprDerivHandler h,
- GnmExprDerivFlags flags,
- gpointer data, GDestroyNotify notify);
-void gnm_expr_deriv_uninstall_handler (GnmFunc *func);
+/* ------------------------------------------------------------------------- */
+
void _gnm_expr_deriv_shutdown (void);
/* ------------------------------------------------------------------------- */
diff --git a/src/func-builtin.c b/src/func-builtin.c
index 3043bcc30..3b2c89304 100644
--- a/src/func-builtin.c
+++ b/src/func-builtin.c
@@ -63,13 +63,12 @@ gnumeric_sum (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
}
static GnmExpr const *
-gnumeric_sum_deriv (GnmExpr const *expr,
+gnumeric_sum_deriv (GnmFunc *func,
+ GnmExpr const *expr,
GnmEvalPos const *ep,
- GnmExprDeriv *info,
- gpointer data)
+ GnmExprDeriv *info)
{
GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info);
- GnmFunc *fsum = gnm_expr_get_func_def (expr);
gboolean bad = FALSE;
for (l = args; l; l = l->next) {
@@ -90,7 +89,7 @@ gnumeric_sum_deriv (GnmExpr const *expr,
gnm_expr_list_free (args);
return NULL;
} else
- return gnm_expr_new_funcall (fsum, args);
+ return gnm_expr_new_funcall (func, args);
}
/***************************************************************************/
@@ -541,7 +540,6 @@ func_builtin_init (void)
const char *gname;
const char *tdomain = GETTEXT_PACKAGE;
int i = 0;
- GnmFunc *table_func;
gname = N_("Mathematics");
math_group = gnm_func_group_fetch (gname, _(gname));
@@ -562,13 +560,11 @@ func_builtin_init (void)
logic_group = gnm_func_group_fetch (gname, _(gname));
gnm_func_add (logic_group, builtins + i++, tdomain);
- table_func = gnm_func_lookup ("table", NULL);
- g_signal_connect (table_func, "link-dep", G_CALLBACK (gnumeric_table_link), NULL);
+ g_signal_connect (gnm_func_lookup ("table", NULL),
+ "link-dep", G_CALLBACK (gnumeric_table_link), NULL);
- gnm_expr_deriv_install_handler (gnm_func_lookup ("sum", NULL),
- gnumeric_sum_deriv,
- GNM_EXPR_DERIV_NO_CHAIN | GNM_EXPR_DERIV_OPTIMIZE,
- NULL, NULL);
+ g_signal_connect (gnm_func_lookup ("sum", NULL),
+ "derivative", G_CALLBACK (gnumeric_sum_deriv), NULL);
}
void
diff --git a/src/func.c b/src/func.c
index b5382bba4..f2d07b92a 100644
--- a/src/func.c
+++ b/src/func.c
@@ -30,6 +30,7 @@
#include <gnm-plugin.h>
#include <gutils.h>
#include <gui-util.h>
+#include <expr-deriv.h>
#include <gnm-marshalers.h>
#include <goffice/goffice.h>
@@ -47,6 +48,7 @@ enum {
enum {
SIG_LOAD_STUB,
SIG_LINK_DEP,
+ SIG_DERIVATIVE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -1782,6 +1784,27 @@ gnm_func_link_dep (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink)
return (GnmDependentFlags)res;
}
+/**
+ * gnm_func_derivative:
+ * @func: #GnmFunc
+ * @expr: expression that calls @func
+ * @ep: position of @expr
+ * @info: #GnmExprDeriv
+ *
+ * Returns: (transfer full) (nullable): the derivative of @expr with respect to
+ * @info.
+ */
+GnmExpr const *
+gnm_func_derivative (GnmFunc *func, GnmExpr const *expr, GnmEvalPos const *ep,
+ GnmExprDeriv *info)
+{
+ GnmExpr *res = NULL;
+
+ g_return_val_if_fail (GNM_IS_FUNC (func), NULL);
+ g_signal_emit (func, signals[SIG_DERIVATIVE], 0, expr, ep, info, &res);
+ return res;
+}
+
/* ------------------------------------------------------------------------- */
static GObjectClass *parent_class;
@@ -1791,6 +1814,7 @@ typedef struct {
void (*load_stub) (GnmFunc *func);
int (*link_dep) (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink);
+ GnmExpr* (*derivative) (GnmFunc *func, GnmExpr const *expr, GnmEvalPos *ep, GnmExprDeriv *info);
} GnmFuncClass;
static void
@@ -1925,6 +1949,14 @@ gnm_func_class_init (GObjectClass *gobject_class)
GSF_PARAM_STATIC |
G_PARAM_READABLE));
+ /**
+ * GnmFunc::load-stub:
+ * @func: the #GnmFunc that needs to be loaded
+ *
+ * Signals that @func, which is a stub, needs to be loaded now. Anyone
+ * creating a stub function should arrange for this signal to be caught
+ * and the function to be properly instantiated.
+ */
signals[SIG_LOAD_STUB] = g_signal_new
("load-stub",
GNM_FUNC_TYPE,
@@ -1934,7 +1966,18 @@ gnm_func_class_init (GObjectClass *gobject_class)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
-
+ /**
+ * GnmFunc::link-dep:
+ * @func: the #GnmFunc that is being linked or unlinked
+ * @ei: #GnmFuncEvalInfo for the call initiating the link or unlink.
+ * @qlink: %TRUE for link, %FALSE for unlink
+ *
+ * Signals that an expressions that is a call to @func is being linked
+ * or unlinked. Most functions do not need this.
+ *
+ * Returns: A #GnmDependentFlags allowing arguments not be be linked if
+ * that is appropriate.
+ */
signals[SIG_LINK_DEP] = g_signal_new
("link-dep",
GNM_FUNC_TYPE,
@@ -1944,6 +1987,28 @@ gnm_func_class_init (GObjectClass *gobject_class)
gnm__INT__POINTER_BOOLEAN,
// GnmDependentFlags ... GnmFuncEvalInfo
G_TYPE_INT, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
+
+ /**
+ * GnmFunc::derivative:
+ * @func: #GnmFunc
+ * @expr: #GnmExpr for the call for which the derivative is sought
+ * @ep: position f @expr
+ * @info: #GnmExprDeriv telling which derivative is sought
+ *
+ * Signals that a function call's derivative should be calculatted
+ *
+ * Returns: (transfer full) (nullable): #GnmExpr representing the
+ * derivative, %NULL for error.
+ */
+ signals[SIG_DERIVATIVE] = g_signal_new
+ ("derivative",
+ GNM_FUNC_TYPE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GnmFuncClass, derivative),
+ NULL, NULL,
+ gnm__BOXED__BOXED_BOXED_BOXED,
+ gnm_expr_get_type(),
+ 3, gnm_expr_get_type(), gnm_eval_pos_get_type(), gnm_expr_deriv_info_get_type());
}
GSF_CLASS (GnmFunc, gnm_func,
diff --git a/src/func.h b/src/func.h
index 5a00e7744..d1f33b9ec 100644
--- a/src/func.h
+++ b/src/func.h
@@ -306,6 +306,13 @@ struct _GnmFuncEvalInfo {
GnmFunc const *gnm_eval_info_get_func (GnmFuncEvalInfo const *ei);
int gnm_eval_info_get_arg_count (GnmFuncEvalInfo const *ei);
+/*************************************************************************/
+
+GnmExpr const *gnm_func_derivative (GnmFunc *func,
+ GnmExpr const *expr, GnmEvalPos const *ep,
+ GnmExprDeriv *info);
+
+
G_END_DECLS
#endif /* _GNM_FUNC_H_ */
diff --git a/src/gnm-marshalers.list b/src/gnm-marshalers.list
index 2655e605e..45b633477 100644
--- a/src/gnm-marshalers.list
+++ b/src/gnm-marshalers.list
@@ -25,3 +25,4 @@ BOOLEAN:OBJECT,POINTER
VOID:BOOLEAN,INT
BOOLEAN:VOID
INT:POINTER,BOOLEAN
+BOXED:BOXED,BOXED,BOXED
diff --git a/src/gnumeric-fwd.h b/src/gnumeric-fwd.h
index c1a83c265..92a99e88d 100644
--- a/src/gnumeric-fwd.h
+++ b/src/gnumeric-fwd.h
@@ -104,6 +104,7 @@ typedef struct _WorkbookView WorkbookView;
typedef union _GnmExpr GnmExpr;
typedef union _GnmValue GnmValue;
typedef struct _GenericToolState GnmGenericToolState;
+typedef struct GnmExprDeriv_ GnmExprDeriv;
typedef GList ColRowIndexList;
typedef GSList ColRowStateGroup;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]