Commit 03f01e38 authored by Morten Welinder's avatar Morten Welinder

Derivative: use a GnmFunc signal instead of ad-hoc handlers.

parent 8c772ce2
...@@ -968,10 +968,10 @@ gnumeric_exp (GnmFuncEvalInfo *ei, GnmValue const * const *argv) ...@@ -968,10 +968,10 @@ gnumeric_exp (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
} }
static GnmExpr const * static GnmExpr const *
gnumeric_exp_deriv (GnmExpr const *expr, GnmEvalPos const *ep, gnumeric_exp_deriv (GnmFunc *func, GnmExpr const *expr, GnmEvalPos const *ep,
GnmExprDeriv *info, gpointer data) 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 * ...@@ -1318,9 +1318,11 @@ static GnmExpr const *
gnumeric_ln_deriv (GnmExpr const *expr, GnmEvalPos const *ep, gnumeric_ln_deriv (GnmExpr const *expr, GnmEvalPos const *ep,
GnmExprDeriv *info, gpointer data) GnmExprDeriv *info, gpointer data)
{ {
return gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)), GnmExpr const *deriv =
GNM_EXPR_OP_DIV, gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)),
gnm_expr_copy (gnm_expr_get_func_arg (expr, 0))); 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) ...@@ -1750,8 +1752,9 @@ gnumeric_sumsq (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
} }
static GnmExpr const * static GnmExpr const *
gnumeric_sumsq_deriv (GnmExpr const *expr, GnmEvalPos const *ep, gnumeric_sumsq_deriv (GnmFunc *func,
GnmExprDeriv *info, gpointer data) GnmExpr const *expr, GnmEvalPos const *ep,
GnmExprDeriv *info)
{ {
GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info); GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info);
GnmExpr const *res; GnmExpr const *res;
...@@ -3742,24 +3745,15 @@ GnmFuncDescriptor const math_functions[] = { ...@@ -3742,24 +3745,15 @@ GnmFuncDescriptor const math_functions[] = {
G_MODULE_EXPORT void G_MODULE_EXPORT void
go_plugin_init (GOPlugin *plugin, GOCmdContext *cc) go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
{ {
gnm_expr_deriv_install_handler (gnm_func_lookup ("sumsq", NULL), g_signal_connect (gnm_func_lookup ("sumsq", NULL),
gnumeric_sumsq_deriv, "derivative", G_CALLBACK (gnumeric_sumsq_deriv), NULL);
GNM_EXPR_DERIV_NO_CHAIN | GNM_EXPR_DERIV_OPTIMIZE, g_signal_connect (gnm_func_lookup ("exp", NULL),
NULL, NULL); "derivative", G_CALLBACK (gnumeric_exp_deriv), NULL);
gnm_expr_deriv_install_handler (gnm_func_lookup ("exp", NULL), g_signal_connect (gnm_func_lookup ("ln", NULL),
gnumeric_exp_deriv, "derivative", G_CALLBACK (gnumeric_ln_deriv), NULL);
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_MODULE_EXPORT void G_MODULE_EXPORT void
go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc) 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));
} }
...@@ -32,25 +32,6 @@ ...@@ -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_ { struct GnmExprDeriv_ {
unsigned ref_count; unsigned ref_count;
GnmEvalPos var; GnmEvalPos var;
...@@ -474,7 +455,7 @@ gnm_expr_deriv_collect (GnmExpr const *expr, ...@@ -474,7 +455,7 @@ gnm_expr_deriv_collect (GnmExpr const *expr,
&user); &user);
} }
return user.args; return g_slist_reverse (user.args);
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
...@@ -494,7 +475,15 @@ gnm_expr_deriv_collect (GnmExpr const *expr, ...@@ -494,7 +475,15 @@ gnm_expr_deriv_collect (GnmExpr const *expr,
#define COMMON_BINARY_END } #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 * GnmExpr const *
gnm_expr_deriv (GnmExpr const *expr, gnm_expr_deriv (GnmExpr const *expr,
GnmEvalPos const *ep, GnmEvalPos const *ep,
...@@ -585,33 +574,12 @@ gnm_expr_deriv (GnmExpr const *expr, ...@@ -585,33 +574,12 @@ gnm_expr_deriv (GnmExpr const *expr,
case GNM_EXPR_OP_FUNCALL: { case GNM_EXPR_OP_FUNCALL: {
GnmFunc *f = gnm_expr_get_func_def (expr); GnmFunc *f = gnm_expr_get_func_def (expr);
struct DerivHandler const *di = deriv_handlers GnmExpr const *res = gnm_func_derivative (f, expr, ep, info);
? g_hash_table_lookup (deriv_handlers, f) GnmExpr const *opt = optimize (res);
: NULL; if (opt) {
GnmExpr const *res = di gnm_expr_free (res);
? di->handler (expr, ep, info, di->data) res = opt;
: 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);
} }
if (di->flags & GNM_EXPR_DERIV_OPTIMIZE) {
GnmExpr const *opt = optimize (res);
if (opt) {
gnm_expr_free (res);
res = opt;
}
}
return res; return res;
} }
...@@ -794,40 +762,35 @@ gnm_expr_cell_deriv_value (GnmCell *y, GnmCell *x) ...@@ -794,40 +762,35 @@ gnm_expr_cell_deriv_value (GnmCell *y, GnmCell *x)
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/** /**
* gnm_expr_deriv_install_handler: * gnm_expr_deriv_chain:
* @func: the function being given a handler * @expr: #GnmExpr for a function call with one argument
* @h: (scope notified): #GnmExprDerivHandler * @deriv: (transfer full) (nullable): Derivative of @expr's function.
* @flags: * @ep: position for @expr
* @data: user data for @h * @info: Derivative information
* @notify: destroy notification for @data *
* Applies the chain rule to @expr.
*
* Returns: (transfer full) (nullable): the derivative of @expr with respect
* to @info.
*/ */
void GnmExpr const *
gnm_expr_deriv_install_handler (GnmFunc *func, GnmExprDerivHandler h, gnm_expr_deriv_chain (GnmExpr const *expr,
GnmExprDerivFlags flags, GnmExpr const *deriv,
gpointer data, GnmEvalPos const *ep,
GDestroyNotify notify) GnmExprDeriv *info)
{ {
struct DerivHandler *hdata; GnmExpr const *deriv2;
if (!deriv_handlers) {
deriv_handlers = g_hash_table_new_full
(g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify)deriv_handler_free);
}
hdata = g_new (struct DerivHandler, 1); if (!deriv)
hdata->handler = h; return NULL;
hdata->flags = flags;
hdata->data = data;
hdata->notify = notify;
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 return mmul (deriv, 0, deriv2, 0);
gnm_expr_deriv_uninstall_handler (GnmFunc *func)
{
g_hash_table_remove (deriv_handlers, func);
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
...@@ -835,10 +798,6 @@ gnm_expr_deriv_uninstall_handler (GnmFunc *func) ...@@ -835,10 +798,6 @@ gnm_expr_deriv_uninstall_handler (GnmFunc *func)
void void
_gnm_expr_deriv_shutdown (void) _gnm_expr_deriv_shutdown (void)
{ {
if (deriv_handlers) {
g_hash_table_destroy (deriv_handlers);
deriv_handlers = NULL;
}
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
...@@ -3,13 +3,12 @@ ...@@ -3,13 +3,12 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#include <gnumeric-fwd.h>
#include <expr.h> #include <expr.h>
#include <numbers.h> #include <numbers.h>
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
typedef struct GnmExprDeriv_ GnmExprDeriv;
GType gnm_expr_deriv_info_get_type (void); GType gnm_expr_deriv_info_get_type (void);
GnmExprDeriv *gnm_expr_deriv_info_new (void); GnmExprDeriv *gnm_expr_deriv_info_new (void);
...@@ -33,26 +32,17 @@ GnmExprTop const *gnm_expr_cell_deriv (GnmCell *y, GnmCell *x); ...@@ -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); 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, GnmExprList *gnm_expr_deriv_collect (GnmExpr const *expr,
GnmEvalPos const *ep, GnmEvalPos const *ep,
GnmExprDeriv *info); 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); void _gnm_expr_deriv_shutdown (void);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
......
...@@ -63,13 +63,12 @@ gnumeric_sum (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv) ...@@ -63,13 +63,12 @@ gnumeric_sum (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
} }
static GnmExpr const * static GnmExpr const *
gnumeric_sum_deriv (GnmExpr const *expr, gnumeric_sum_deriv (GnmFunc *func,
GnmExpr const *expr,
GnmEvalPos const *ep, GnmEvalPos const *ep,
GnmExprDeriv *info, GnmExprDeriv *info)
gpointer data)
{ {
GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info); GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info);
GnmFunc *fsum = gnm_expr_get_func_def (expr);
gboolean bad = FALSE; gboolean bad = FALSE;
for (l = args; l; l = l->next) { for (l = args; l; l = l->next) {
...@@ -90,7 +89,7 @@ gnumeric_sum_deriv (GnmExpr const *expr, ...@@ -90,7 +89,7 @@ gnumeric_sum_deriv (GnmExpr const *expr,
gnm_expr_list_free (args); gnm_expr_list_free (args);
return NULL; return NULL;
} else } else
return gnm_expr_new_funcall (fsum, args); return gnm_expr_new_funcall (func, args);
} }
/***************************************************************************/ /***************************************************************************/
...@@ -541,7 +540,6 @@ func_builtin_init (void) ...@@ -541,7 +540,6 @@ func_builtin_init (void)
const char *gname; const char *gname;
const char *tdomain = GETTEXT_PACKAGE; const char *tdomain = GETTEXT_PACKAGE;
int i = 0; int i = 0;
GnmFunc *table_func;
gname = N_("Mathematics"); gname = N_("Mathematics");
math_group = gnm_func_group_fetch (gname, _(gname)); math_group = gnm_func_group_fetch (gname, _(gname));
...@@ -562,13 +560,11 @@ func_builtin_init (void) ...@@ -562,13 +560,11 @@ func_builtin_init (void)
logic_group = gnm_func_group_fetch (gname, _(gname)); logic_group = gnm_func_group_fetch (gname, _(gname));
gnm_func_add (logic_group, builtins + i++, tdomain); gnm_func_add (logic_group, builtins + i++, tdomain);
table_func = gnm_func_lookup ("table", NULL); g_signal_connect (gnm_func_lookup ("table", NULL),
g_signal_connect (table_func, "link-dep", G_CALLBACK (gnumeric_table_link), NULL); "link-dep", G_CALLBACK (gnumeric_table_link), NULL);
gnm_expr_deriv_install_handler (gnm_func_lookup ("sum", NULL), g_signal_connect (gnm_func_lookup ("sum", NULL),
gnumeric_sum_deriv, "derivative", G_CALLBACK (gnumeric_sum_deriv), NULL);
GNM_EXPR_DERIV_NO_CHAIN | GNM_EXPR_DERIV_OPTIMIZE,
NULL, NULL);
} }
void void
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <gnm-plugin.h> #include <gnm-plugin.h>
#include <gutils.h> #include <gutils.h>
#include <gui-util.h> #include <gui-util.h>
#include <expr-deriv.h>
#include <gnm-marshalers.h> #include <gnm-marshalers.h>
#include <goffice/goffice.h> #include <goffice/goffice.h>
...@@ -47,6 +48,7 @@ enum { ...@@ -47,6 +48,7 @@ enum {
enum { enum {
SIG_LOAD_STUB, SIG_LOAD_STUB,
SIG_LINK_DEP, SIG_LINK_DEP,
SIG_DERIVATIVE,
LAST_SIGNAL LAST_SIGNAL
}; };
static guint signals[LAST_SIGNAL] = { 0 }; static guint signals[LAST_SIGNAL] = { 0 };
...@@ -1782,6 +1784,27 @@ gnm_func_link_dep (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink) ...@@ -1782,6 +1784,27 @@ gnm_func_link_dep (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink)
return (GnmDependentFlags)res; 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; static GObjectClass *parent_class;
...@@ -1791,6 +1814,7 @@ typedef struct { ...@@ -1791,6 +1814,7 @@ typedef struct {
void (*load_stub) (GnmFunc *func); void (*load_stub) (GnmFunc *func);
int (*link_dep) (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink); int (*link_dep) (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink);
GnmExpr* (*derivative) (GnmFunc *func, GnmExpr const *expr, GnmEvalPos *ep, GnmExprDeriv *info);
} GnmFuncClass; } GnmFuncClass;
static void static void
...@@ -1925,6 +1949,14 @@ gnm_func_class_init (GObjectClass *gobject_class) ...@@ -1925,6 +1949,14 @@ gnm_func_class_init (GObjectClass *gobject_class)
GSF_PARAM_STATIC | GSF_PARAM_STATIC |
G_PARAM_READABLE)); 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 signals[SIG_LOAD_STUB] = g_signal_new
("load-stub", ("load-stub",
GNM_FUNC_TYPE, GNM_FUNC_TYPE,
...@@ -1934,7 +1966,18 @@ gnm_func_class_init (GObjectClass *gobject_class) ...@@ -1934,7 +1966,18 @@ gnm_func_class_init (GObjectClass *gobject_class)
g_cclosure_marshal_VOID__VOID, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0); 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 signals[SIG_LINK_DEP] = g_signal_new
("link-dep", ("link-dep",
GNM_FUNC_TYPE, GNM_FUNC_TYPE,
...@@ -1944,6 +1987,28 @@ gnm_func_class_init (GObjectClass *gobject_class) ...@@ -1944,6 +1987,28 @@ gnm_func_class_init (GObjectClass *gobject_class)
gnm__INT__POINTER_BOOLEAN, gnm__INT__POINTER_BOOLEAN,
// GnmDependentFlags ... GnmFuncEvalInfo // GnmDependentFlags ... GnmFuncEvalInfo
G_TYPE_INT, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN); 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, GSF_CLASS (GnmFunc, gnm_func,
......
...@@ -306,6 +306,13 @@ struct _GnmFuncEvalInfo { ...@@ -306,6 +306,13 @@ struct _GnmFuncEvalInfo {
GnmFunc const *gnm_eval_info_get_func (GnmFuncEvalInfo const *ei); GnmFunc const *gnm_eval_info_get_func (GnmFuncEvalInfo const *ei);
int gnm_eval_info_get_arg_count (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 G_END_DECLS
#endif /* _GNM_FUNC_H_ */ #endif /* _GNM_FUNC_H_ */
...@@ -25,3 +25,4 @@ BOOLEAN:OBJECT,POINTER ...@@ -25,3 +25,4 @@ BOOLEAN:OBJECT,POINTER
VOID:BOOLEAN,INT VOID:BOOLEAN,INT
BOOLEAN:VOID BOOLEAN:VOID
INT:POINTER,BOOLEAN INT:POINTER,BOOLEAN
BOXED:BOXED,BOXED,BOXED
...@@ -104,6 +104,7 @@ typedef struct _WorkbookView WorkbookView; ...@@ -104,6 +104,7 @@ typedef struct _WorkbookView WorkbookView;
typedef union _GnmExpr GnmExpr; typedef union _GnmExpr GnmExpr;
typedef union _GnmValue GnmValue; typedef union _GnmValue GnmValue;
typedef struct _GenericToolState GnmGenericToolState; typedef struct _GenericToolState GnmGenericToolState;
typedef struct GnmExprDeriv_ GnmExprDeriv;
typedef GList ColRowIndexList; typedef GList ColRowIndexList;
typedef GSList ColRowStateGroup; typedef GSList ColRowStateGroup;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment