[gnumeric] Solver: refactor idle-loop handling into a solver subclass.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] Solver: refactor idle-loop handling into a solver subclass.
- Date: Sat, 25 Apr 2015 00:56:46 +0000 (UTC)
commit 5406d4b777bb0c1f36c04b5992b07a8c76731725
Author: Morten Welinder <terra gnome org>
Date: Fri Apr 24 20:56:15 2015 -0400
Solver: refactor idle-loop handling into a solver subclass.
plugins/nlsolve/ChangeLog | 4 +
plugins/nlsolve/gnm-nlsolve.c | 91 +++++----------------
src/gnm-marshalers.list | 1 +
src/tools/ChangeLog | 1 +
src/tools/gnm-solver.c | 172 ++++++++++++++++++++++++++++++++++++++---
src/tools/gnm-solver.h | 26 ++++++-
6 files changed, 213 insertions(+), 82 deletions(-)
---
diff --git a/plugins/nlsolve/ChangeLog b/plugins/nlsolve/ChangeLog
index 7e87130..4dc2acc 100644
--- a/plugins/nlsolve/ChangeLog
+++ b/plugins/nlsolve/ChangeLog
@@ -1,3 +1,7 @@
+2015-04-24 Morten Welinder <terra gnome org>
+
+ * gnm-nlsolve.c: Recast in terms of GnmIterSolver.
+
2015-04-16 Morten Welinder <terra gnome org>
* Release 1.12.22
diff --git a/plugins/nlsolve/gnm-nlsolve.c b/plugins/nlsolve/gnm-nlsolve.c
index ece76c7..ff7401d 100644
--- a/plugins/nlsolve/gnm-nlsolve.c
+++ b/plugins/nlsolve/gnm-nlsolve.c
@@ -41,7 +41,7 @@
typedef struct {
- GnmSolver *parent;
+ GnmIterSolver *parent;
/* Input/output cells. */
GPtrArray *vars;
@@ -55,7 +55,6 @@ typedef struct {
/* Current point. */
gnm_float *xk, yk;
- int k;
/* Rosenbrock state */
gnm_float **xi;
@@ -65,29 +64,17 @@ typedef struct {
/* Parameters: */
gboolean debug;
- int max_iter;
+ guint64 max_iter;
gnm_float min_factor;
-
- guint idle_tag;
} GnmNlsolve;
static void free_matrix (gnm_float **m, int n);
static void
-gnm_nlsolve_cleanup (GnmNlsolve *nl)
-{
- if (nl->idle_tag) {
- g_source_remove (nl->idle_tag);
- nl->idle_tag = 0;
- }
-}
-
-static void
gnm_nlsolve_final (GnmNlsolve *nl)
{
const int n = nl->vars->len;
- gnm_nlsolve_cleanup (nl);
if (nl->vars)
g_ptr_array_free (nl->vars, TRUE);
g_free (nl->xk);
@@ -187,7 +174,7 @@ free_matrix (gnm_float **m, int n)
static void
gnm_nlsolve_set_solution (GnmNlsolve *nl)
{
- GnmSolver *sol = nl->parent;
+ GnmSolver *sol = GNM_SOLVER (nl->parent);
GnmSolverResult *result = g_object_new (GNM_SOLVER_RESULT_TYPE, NULL);
const int n = nl->vars->len;
int i;
@@ -215,7 +202,7 @@ gnm_nlsolve_set_solution (GnmNlsolve *nl)
static gboolean
gnm_nlsolve_get_initial_solution (GnmNlsolve *nl, GError **err)
{
- GnmSolver *sol = nl->parent;
+ GnmSolver *sol = GNM_SOLVER (nl->parent);
const int n = nl->vars->len;
int i;
@@ -258,7 +245,6 @@ gnm_nlsolve_prepare (GnmSolver *sol, WorkbookControl *wbc, GError **err,
if (ok) {
gnm_solver_set_status (sol, GNM_SOLVER_STATUS_PREPARED);
} else {
- gnm_nlsolve_cleanup (nl);
gnm_solver_set_status (sol, GNM_SOLVER_STATUS_ERROR);
}
@@ -344,7 +330,7 @@ compute_hessian (GnmNlsolve *nl, const gnm_float *xs, const gnm_float *g0)
static gboolean
newton_improve (GnmNlsolve *nl, gnm_float *xs, gnm_float *y, gnm_float ymax)
{
- GnmSolver *sol = nl->parent;
+ GnmSolver *sol = GNM_SOLVER (nl->parent);
const int n = nl->vars->len;
gnm_float *g, **H, *d;
gboolean ok;
@@ -438,7 +424,8 @@ rosenbrock_tentative_end (GnmNlsolve *nl, gboolean accept)
static gboolean
rosenbrock_iter (GnmNlsolve *nl)
{
- GnmSolver *sol = nl->parent;
+ GnmSolver *sol = GNM_SOLVER (nl->parent);
+ GnmIterSolver *isol = GNM_ITER_SOLVER (sol);
const int n = nl->vars->len;
int i, j;
const gnm_float alpha = 3;
@@ -460,7 +447,7 @@ rosenbrock_iter (GnmNlsolve *nl)
}
}
- if (nl->k % 20 == 0) {
+ if (isol->iterations % 20 == 0) {
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
nl->xi[i][j] = (i == j);
@@ -647,7 +634,7 @@ rosenbrock_shutdown (GnmNlsolve *nl)
static gboolean
polish_iter (GnmNlsolve *nl)
{
- GnmSolver *sol = nl->parent;
+ GnmSolver *sol = GNM_SOLVER (nl->parent);
const int n = nl->vars->len;
gnm_float *x;
gnm_float step;
@@ -692,25 +679,23 @@ polish_iter (GnmNlsolve *nl)
return any_at_all;
}
-static gint
-gnm_nlsolve_idle (gpointer data)
+static void
+gnm_nlsolve_iterate (GnmIterSolver *isol, GnmNlsolve *nl)
{
- GnmNlsolve *nl = data;
- GnmSolver *sol = nl->parent;
+ GnmSolver *sol = GNM_SOLVER (isol);
const int n = nl->vars->len;
gboolean ok;
gboolean call_again = TRUE;
- if (nl->k == 0)
+ if (isol->iterations == 0)
rosenbrock_init (nl);
if (nl->debug) {
- g_printerr ("Iteration %d at %.15" GNM_FORMAT_g "\n",
- nl->k, nl->yk);
+ g_printerr ("Iteration %ld at %.15" GNM_FORMAT_g "\n",
+ (long)(isol->iterations), nl->yk);
print_vector ("Current point", nl->xk, n);
}
- nl->k++;
ok = rosenbrock_iter (nl);
if (!ok && !nl->tentative) {
@@ -722,7 +707,7 @@ gnm_nlsolve_idle (gpointer data)
call_again = FALSE;
}
- if (call_again && nl->k >= nl->max_iter) {
+ if (call_again && isol->iterations >= nl->max_iter) {
gnm_solver_set_status (sol, GNM_SOLVER_STATUS_DONE);
call_again = FALSE;
}
@@ -733,37 +718,6 @@ gnm_nlsolve_idle (gpointer data)
rosenbrock_shutdown (nl);
}
-
- if (!call_again)
- nl->idle_tag = 0;
-
- return call_again;
-}
-
-static gboolean
-gnm_nlsolve_start (GnmSolver *sol, WorkbookControl *wbc, GError **err,
- GnmNlsolve *nl)
-{
- gboolean ok = TRUE;
-
- g_return_val_if_fail (sol->status == GNM_SOLVER_STATUS_PREPARED, FALSE);
-
- nl->idle_tag = g_idle_add (gnm_nlsolve_idle, nl);
- gnm_solver_set_status (sol, GNM_SOLVER_STATUS_RUNNING);
-
- return ok;
-}
-
-static gboolean
-gnm_nlsolve_stop (GnmSolver *sol, GError *err, GnmNlsolve *nl)
-{
- g_return_val_if_fail (sol->status == GNM_SOLVER_STATUS_RUNNING, FALSE);
-
- gnm_nlsolve_cleanup (nl);
-
- gnm_solver_set_status (sol, GNM_SOLVER_STATUS_CANCELLED);
-
- return TRUE;
}
gboolean
@@ -782,9 +736,9 @@ nlsolve_solver_factory (GnmSolverFactory *factory, GnmSolverParameters *params);
GnmSolver *
nlsolve_solver_factory (GnmSolverFactory *factory, GnmSolverParameters *params)
{
- GnmSolver *res = g_object_new (GNM_SOLVER_TYPE,
- "params", params,
- NULL);
+ GnmIterSolver *res = g_object_new (GNM_ITER_SOLVER_TYPE,
+ "params", params,
+ NULL);
GnmNlsolve *nl = g_new0 (GnmNlsolve, 1);
GSList *input_cells, *l;
int n;
@@ -792,7 +746,7 @@ nlsolve_solver_factory (GnmSolverFactory *factory, GnmSolverParameters *params)
GnmEvalPos ep;
GnmCellRef origin;
- nl->parent = GNM_SOLVER (res);
+ nl->parent = res;
nl->maximize = (params->problem_type == GNM_SOLVER_MAXIMIZE);
@@ -822,11 +776,10 @@ nlsolve_solver_factory (GnmSolverFactory *factory, GnmSolverParameters *params)
nl->xk = g_new (gnm_float, n);
g_signal_connect (res, "prepare", G_CALLBACK (gnm_nlsolve_prepare), nl);
- g_signal_connect (res, "start", G_CALLBACK (gnm_nlsolve_start), nl);
- g_signal_connect (res, "stop", G_CALLBACK (gnm_nlsolve_stop), nl);
+ g_signal_connect (res, "iterate", G_CALLBACK (gnm_nlsolve_iterate), nl);
g_object_set_data_full (G_OBJECT (res), PRIVATE_KEY, nl,
(GDestroyNotify)gnm_nlsolve_final);
- return res;
+ return GNM_SOLVER (res);
}
diff --git a/src/gnm-marshalers.list b/src/gnm-marshalers.list
index 52c2879..8961862 100644
--- a/src/gnm-marshalers.list
+++ b/src/gnm-marshalers.list
@@ -23,3 +23,4 @@
BOOLEAN:POINTER
BOOLEAN:OBJECT,POINTER
VOID:BOOLEAN,INT
+VOID:VOID
diff --git a/src/tools/ChangeLog b/src/tools/ChangeLog
index 3b48b1f..385d9ad 100644
--- a/src/tools/ChangeLog
+++ b/src/tools/ChangeLog
@@ -4,6 +4,7 @@
function.
(gnm_solver_check_constraints): Avoid undefined C behaviour.
(gnm_solver_param_get_input_cells): Avoid O(n^2) list handling.
+ (gnm_iter_solver_class_init): New class for in-process solvers.
2015-04-16 Morten Welinder <terra gnome org>
diff --git a/src/tools/gnm-solver.c b/src/tools/gnm-solver.c
index 5bdabc1..d0279f1 100644
--- a/src/tools/gnm-solver.c
+++ b/src/tools/gnm-solver.c
@@ -767,7 +767,6 @@ enum {
SOL_SIG_PREPARE,
SOL_SIG_START,
SOL_SIG_STOP,
- SOL_SIG_CHILD_EXIT,
SOL_SIG_LAST
};
@@ -889,6 +888,18 @@ gnm_solver_set_property (GObject *object, guint property_id,
}
}
+/**
+ * gnm_solver_prepare:
+ * @sol: solver
+ * @wbc: control for user interaction
+ * @err: location to store error
+ *
+ * Prepare for solving. Preparation need not do anything, but may include
+ * such tasks as checking that the model is valid for the solver and
+ * locating necessary external programs.
+ *
+ * Returns: %TRUE ok success, %FALSE on error.
+ */
gboolean
gnm_solver_prepare (GnmSolver *sol, WorkbookControl *wbc, GError **err)
{
@@ -901,6 +912,16 @@ gnm_solver_prepare (GnmSolver *sol, WorkbookControl *wbc, GError **err)
return res;
}
+/**
+ * gnm_solver_start:
+ * @sol: solver
+ * @wbc: control for user interaction
+ * @err: location to store error
+ *
+ * Start the solving process. If needed, the solver will be prepared first.
+ *
+ * Returns: %TRUE ok success, %FALSE on error.
+ */
gboolean
gnm_solver_start (GnmSolver *sol, WorkbookControl *wbc, GError **err)
{
@@ -922,6 +943,15 @@ gnm_solver_start (GnmSolver *sol, WorkbookControl *wbc, GError **err)
return res;
}
+/**
+ * gnm_solver_stop:
+ * @sol: solver
+ * @err: location to store error
+ *
+ * Terminate the currently-running solver.
+ *
+ * Returns: %TRUE ok success, %FALSE on error.
+ */
gboolean
gnm_solver_stop (GnmSolver *sol, GError **err)
{
@@ -1700,16 +1730,6 @@ gnm_solver_class_init (GObjectClass *object_class)
gnm__BOOLEAN__POINTER,
G_TYPE_BOOLEAN, 1,
G_TYPE_POINTER);
-
- solver_signals[SOL_SIG_CHILD_EXIT] =
- g_signal_new ("child-exit",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GnmSolverClass, child_exit),
- NULL, NULL,
- gnm__VOID__BOOLEAN_INT,
- G_TYPE_NONE, 2,
- G_TYPE_BOOLEAN, G_TYPE_INT);
}
GSF_CLASS (GnmSolver, gnm_solver,
@@ -1743,6 +1763,13 @@ GSF_CLASS (GnmSolverResult, gnm_solver_result,
static GObjectClass *gnm_sub_solver_parent_class;
+enum {
+ SUB_SOL_SIG_CHILD_EXIT,
+ SUB_SOL_SIG_LAST
+};
+
+static guint sub_solver_signals[SUB_SOL_SIG_LAST] = { 0 };
+
void
gnm_sub_solver_clear (GnmSubSolver *subsol)
{
@@ -1862,7 +1889,7 @@ cb_child_exit (G_GNUC_UNUSED GPid pid, gint status, GnmSubSolver *subsol)
status);
}
- g_signal_emit (subsol, solver_signals[SOL_SIG_CHILD_EXIT], 0,
+ g_signal_emit (subsol, sub_solver_signals[SUB_SOL_SIG_CHILD_EXIT], 0,
normal, code);
if (subsol->child_pid) {
@@ -2081,6 +2108,16 @@ gnm_sub_solver_class_init (GObjectClass *object_class)
object_class->dispose = gnm_sub_solver_dispose;
object_class->finalize = gnm_sub_solver_finalize;
+
+ sub_solver_signals[SUB_SOL_SIG_CHILD_EXIT] =
+ g_signal_new ("child-exit",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GnmSubSolverClass, child_exit),
+ NULL, NULL,
+ gnm__VOID__BOOLEAN_INT,
+ G_TYPE_NONE, 2,
+ G_TYPE_BOOLEAN, G_TYPE_INT);
}
GSF_CLASS (GnmSubSolver, gnm_sub_solver,
@@ -2088,6 +2125,117 @@ GSF_CLASS (GnmSubSolver, gnm_sub_solver,
/* ------------------------------------------------------------------------- */
+static GObjectClass *gnm_iter_solver_parent_class;
+
+enum {
+ ITER_SOL_SIG_ITERATE,
+ ITER_SOL_SIG_LAST
+};
+
+static guint iter_solver_signals[ITER_SOL_SIG_LAST] = { 0 };
+
+static void
+gnm_iter_solver_clear (GnmIterSolver *isol)
+{
+ if (isol->idle_tag) {
+ g_source_remove (isol->idle_tag);
+ isol->idle_tag = 0;
+ }
+}
+
+static void
+gnm_iter_solver_dispose (GObject *obj)
+{
+ GnmIterSolver *isol = GNM_ITER_SOLVER (obj);
+ gnm_iter_solver_clear (isol);
+ gnm_iter_solver_parent_class->dispose (obj);
+}
+
+static void
+gnm_iter_solver_finalize (GObject *obj)
+{
+ GnmIterSolver *isol = GNM_ITER_SOLVER (obj);
+ (void)isol;
+ gnm_iter_solver_parent_class->finalize (obj);
+}
+
+static void
+gnm_iter_solver_init (GnmIterSolver *isol)
+{
+}
+
+static gint
+gnm_iter_solver_idle (gpointer data)
+{
+ GnmIterSolver *isol = data;
+ GnmSolver *sol = &isol->parent;
+
+ g_signal_emit (isol, iter_solver_signals[ITER_SOL_SIG_ITERATE], 0);
+
+ isol->iterations++;
+
+ if (gnm_solver_finished (sol)) {
+ isol->idle_tag = 0;
+ return FALSE;
+ } else {
+ /* Call again. */
+ return TRUE;
+ }
+}
+
+static gboolean
+gnm_iter_solver_start (GnmSolver *solver, WorkbookControl *wbc, GError **err)
+{
+ GnmIterSolver *isol = GNM_ITER_SOLVER (solver);
+
+ g_return_val_if_fail (isol->idle_tag == 0, FALSE);
+
+ isol->idle_tag = g_idle_add (gnm_iter_solver_idle, solver);
+ gnm_solver_set_status (solver, GNM_SOLVER_STATUS_RUNNING);
+
+ return TRUE;
+}
+
+static gboolean
+gnm_iter_solver_stop (GnmSolver *solver, GError **err)
+{
+ GnmIterSolver *isol = GNM_ITER_SOLVER (solver);
+ GnmSolver *sol = &isol->parent;
+
+ gnm_iter_solver_clear (isol);
+
+ gnm_solver_set_status (sol, GNM_SOLVER_STATUS_CANCELLED);
+
+ return TRUE;
+}
+
+static void
+gnm_iter_solver_class_init (GObjectClass *object_class)
+{
+ GnmSolverClass *sclass = (GnmSolverClass *)object_class;
+
+ gnm_iter_solver_parent_class = g_type_class_peek_parent (object_class);
+
+ object_class->dispose = gnm_iter_solver_dispose;
+ object_class->finalize = gnm_iter_solver_finalize;
+ sclass->start = gnm_iter_solver_start;
+ sclass->stop = gnm_iter_solver_stop;
+
+ iter_solver_signals[ITER_SOL_SIG_ITERATE] =
+ g_signal_new ("iterate",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GnmIterSolverClass, iterate),
+ NULL, NULL,
+ gnm__VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+GSF_CLASS (GnmIterSolver, gnm_iter_solver,
+ gnm_iter_solver_class_init, gnm_iter_solver_init, GNM_SOLVER_TYPE)
+
+/* ------------------------------------------------------------------------- */
+
static GObjectClass *gnm_solver_factory_parent_class;
static void
diff --git a/src/tools/gnm-solver.h b/src/tools/gnm-solver.h
index c8c7551..ca9a9b2 100644
--- a/src/tools/gnm-solver.h
+++ b/src/tools/gnm-solver.h
@@ -210,7 +210,6 @@ typedef struct {
gboolean (*start) (GnmSolver *solver,
WorkbookControl *wbc, GError **err);
gboolean (*stop) (GnmSolver *solver, GError **err);
- void (*child_exit) (GnmSolver *solver, gboolean normal, int code);
} GnmSolverClass;
GType gnm_solver_get_type (void);
@@ -274,6 +273,8 @@ typedef struct {
typedef struct {
GnmSolverClass parent_class;
+
+ void (*child_exit) (GnmSubSolver *subsol, gboolean normal, int code);
} GnmSubSolverClass;
GType gnm_sub_solver_get_type (void);
@@ -302,6 +303,29 @@ char *gnm_sub_solver_locate_binary (const char *binary, const char *solver,
WBCGtk *wbcg);
/* ------------------------------------------------------------------------- */
+/* Solver subclass for iterative in-process solvers. */
+
+#define GNM_ITER_SOLVER_TYPE (gnm_iter_solver_get_type ())
+#define GNM_ITER_SOLVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GNM_ITER_SOLVER_TYPE, GnmIterSolver))
+#define GNM_IS_ITER_SOLVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNM_ITER_SOLVER_TYPE))
+
+typedef struct {
+ GnmSolver parent;
+
+ guint64 iterations;
+
+ guint idle_tag;
+} GnmIterSolver;
+
+typedef struct {
+ GnmSolverClass parent_class;
+
+ void (*iterate) (GnmIterSolver *isol);
+} GnmIterSolverClass;
+
+GType gnm_iter_solver_get_type (void);
+
+/* ------------------------------------------------------------------------- */
#define GNM_SOLVER_FACTORY_TYPE (gnm_solver_factory_get_type ())
#define GNM_SOLVER_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GNM_SOLVER_FACTORY_TYPE,
GnmSolverFactory))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]