[gnumeric] GoalSeek: code cleanup.



commit bc61e8b974f31d519354436acdb18b67c3754027
Author: Morten Welinder <terra gnome org>
Date:   Fri May 18 08:50:49 2018 -0400

    GoalSeek: code cleanup.
    
    Move non-gui part of the code out of dialogs.

 src/dialogs/dialog-goal-seek.c |  164 +-------------------------------------
 src/tools/goal-seek.c          |  169 +++++++++++++++++++++++++++++++++++-----
 src/tools/goal-seek.h          |   69 ++++++++++-------
 3 files changed, 194 insertions(+), 208 deletions(-)
---
diff --git a/src/dialogs/dialog-goal-seek.c b/src/dialogs/dialog-goal-seek.c
index 96d1dcb..705fa9c 100644
--- a/src/dialogs/dialog-goal-seek.c
+++ b/src/dialogs/dialog-goal-seek.c
@@ -86,175 +86,21 @@ typedef struct {
 } GoalSeekState;
 
 
-typedef struct {
-       GoalSeekState   *state;
-       GnmCell *xcell, *ycell;
-       gnm_float       ytarget;
-       gboolean        update_ui;
-} GoalEvalData;
-
-static GnmGoalSeekStatus
-goal_seek_eval (gnm_float x, gnm_float *y, void *vevaldata)
-{
-       GoalEvalData const *evaldata = vevaldata;
-       GnmValue *v = value_new_float (x);
-
-       if (evaldata->update_ui) {
-               sheet_cell_set_value (evaldata->xcell, v);
-       } else {
-               gnm_cell_set_value (evaldata->xcell, v);
-               cell_queue_recalc (evaldata->xcell);
-       }
-       gnm_cell_eval (evaldata->ycell);
-
-       if (evaldata->ycell->value) {
-               *y = value_get_as_float (evaldata->ycell->value) - evaldata->ytarget;
-               if (gnm_finite (*y))
-                       return GOAL_SEEK_OK;
-       }
-
-       return GOAL_SEEK_ERROR;
-}
-
-
 static GnmGoalSeekStatus
 gnumeric_goal_seek (GoalSeekState *state)
 {
        GnmGoalSeekData seekdata;
-       GoalEvalData evaldata;
-       GnmGoalSeekStatus status;
-       gboolean hadold;
-       gnm_float oldx;
+       GnmGoalSeekCellData celldata;
 
        goal_seek_initialize (&seekdata);
        seekdata.xmin = state->xmin;
        seekdata.xmax = state->xmax;
 
-       evaldata.xcell = state->change_cell;
-       evaldata.ycell = state->set_cell;
-       evaldata.ytarget = state->target_value;
-       evaldata.update_ui = FALSE;
-       evaldata.state = state;
-
-       hadold = !VALUE_IS_EMPTY_OR_ERROR (state->change_cell->value);
-       oldx = hadold ? value_get_as_float (state->change_cell->value) : 0;
-
-       /* PLAN A: Newton's iterative method from initial or midpoint.  */
-       {
-               gnm_float x0;
-
-               if (hadold && oldx >= seekdata.xmin && oldx <= seekdata.xmax)
-                       x0 = oldx;
-               else
-                       x0 = (seekdata.xmin + seekdata.xmax) / 2;
-
-               status = goal_seek_newton (goal_seek_eval, NULL,
-                                          &seekdata, &evaldata,
-                                          x0);
-               if (status == GOAL_SEEK_OK)
-                       goto DONE;
-       }
-
-       /* PLAN B: Trawl uniformly.  */
-       if (!seekdata.havexpos || !seekdata.havexneg) {
-               status = goal_seek_trawl_uniformly (goal_seek_eval,
-                                                   &seekdata, &evaldata,
-                                                   seekdata.xmin, seekdata.xmax,
-                                                   100);
-               if (status == GOAL_SEEK_OK)
-                       goto DONE;
-       }
-
-       /* PLAN C: Trawl normally from middle.  */
-       if (!seekdata.havexpos || !seekdata.havexneg) {
-               gnm_float sigma, mu;
-               int i;
-
-               sigma = MIN (seekdata.xmax - seekdata.xmin, 1e6);
-               mu = (seekdata.xmax + seekdata.xmin) / 2;
-
-               for (i = 0; i < 5; i++) {
-                       sigma /= 10;
-                       status = goal_seek_trawl_normally (goal_seek_eval,
-                                                          &seekdata, &evaldata,
-                                                          mu, sigma, 30);
-                       if (status == GOAL_SEEK_OK)
-                               goto DONE;
-               }
-       }
-
-       /* PLAN D: Trawl normally from left.  */
-       if (!seekdata.havexpos || !seekdata.havexneg) {
-               gnm_float sigma, mu;
-               int i;
-
-               sigma = MIN (seekdata.xmax - seekdata.xmin, 1e6);
-               mu = seekdata.xmin;
-
-               for (i = 0; i < 5; i++) {
-                       sigma /= 10;
-                       status = goal_seek_trawl_normally (goal_seek_eval,
-                                                          &seekdata, &evaldata,
-                                                          mu, sigma, 20);
-                       if (status == GOAL_SEEK_OK)
-                               goto DONE;
-               }
-       }
-
-       /* PLAN E: Trawl normally from right.  */
-       if (!seekdata.havexpos || !seekdata.havexneg) {
-               gnm_float sigma, mu;
-               int i;
-
-               sigma = MIN (seekdata.xmax - seekdata.xmin, 1e6);
-               mu = seekdata.xmax;
-
-               for (i = 0; i < 5; i++) {
-                       sigma /= 10;
-                       status = goal_seek_trawl_normally (goal_seek_eval,
-                                                          &seekdata, &evaldata,
-                                                          mu, sigma, 20);
-                       if (status == GOAL_SEEK_OK)
-                               goto DONE;
-               }
-       }
-
-       /* PLAN F: Newton iteration with uniform net of starting points.  */
-       if (!seekdata.havexpos || !seekdata.havexneg) {
-               int i;
-               const int N = 10;
-
-               for (i = 1; i <= N; i++) {
-                       gnm_float x0 =  seekdata.xmin +
-                               (seekdata.xmax - seekdata.xmin) / (N + 1) * i;
-
-                       status = goal_seek_newton (goal_seek_eval, NULL,
-                                                  &seekdata, &evaldata,
-                                                  x0);
-                       if (status == GOAL_SEEK_OK)
-                               goto DONE;
-               }
-       }
-
-       /* PLAN Z: Bisection.  */
-       {
-               status = goal_seek_bisection (goal_seek_eval,
-                                             &seekdata, &evaldata);
-               if (status == GOAL_SEEK_OK)
-                       goto DONE;
-       }
-
- DONE:
-       evaldata.update_ui = TRUE;
-       if (status == GOAL_SEEK_OK) {
-               gnm_float yroot;
-               (void) goal_seek_eval (seekdata.root, &yroot, &evaldata);
-       } else if (hadold) {
-               gnm_float ydummy;
-               (void) goal_seek_eval (oldx, &ydummy, &evaldata);
-       }
+       celldata.xcell = state->change_cell;
+       celldata.ycell = state->set_cell;
+       celldata.ytarget = state->target_value;
 
-       return status;
+       return gnm_goal_seek_cell (&seekdata, &celldata);
 }
 
 static void
diff --git a/src/tools/goal-seek.c b/src/tools/goal-seek.c
index 4076473..67b6db9 100644
--- a/src/tools/goal-seek.c
+++ b/src/tools/goal-seek.c
@@ -16,6 +16,9 @@
 #include <gnumeric.h>
 #include <tools/goal-seek.h>
 #include <gnm-random.h>
+#include <value.h>
+#include <cell.h>
+#include <sheet.h>
 
 #include <stdlib.h>
 #include <math.h>
@@ -725,35 +728,159 @@ goal_seek_trawl_normally (GnmGoalSeekFunction f,
        return GOAL_SEEK_ERROR;
 }
 
-#ifdef STANDALONE
-static GnmGoalSeekStatus
-f (gnm_float x, gnm_float *y, void *user_data)
+/**
+ * gnm_goal_seek_eval_cell:
+ * @x: x-value for which to evaluate
+ * @y: (out): location to store result
+ * @data: user data
+ *
+ * Returns: An status indicating whether evaluation went ok.
+ */
+GnmGoalSeekStatus
+gnm_goal_seek_eval_cell (gnm_float x, gnm_float *y, gpointer data_)
 {
-       *y = x * x - 2;
-       return GOAL_SEEK_OK;
+       GnmGoalSeekCellData const *data = data_;
+       GnmValue *v = value_new_float (x);
+
+       gnm_cell_set_value (data->xcell, v);
+       cell_queue_recalc (data->xcell);
+       gnm_cell_eval (data->ycell);
+
+       if (data->ycell->value &&
+           VALUE_IS_NUMBER (data->ycell->value)) {
+               *y = value_get_as_float (data->ycell->value) - data->ytarget;
+               if (gnm_finite (*y))
+                       return GOAL_SEEK_OK;
+       }
+
+       return GOAL_SEEK_ERROR;
 }
 
-static GnmGoalSeekStatus
-df (gnm_float x, gnm_float *y, void *user_data)
+GnmGoalSeekStatus
+gnm_goal_seek_cell (GnmGoalSeekData *data,
+                   GnmGoalSeekCellData *celldata)
 {
-       *y = 2 * x;
-       return GOAL_SEEK_OK;
-}
+       GnmGoalSeekStatus status;
+       gboolean hadold;
+       gnm_float oldx;
+       GnmValue *v;
 
+       hadold = !VALUE_IS_EMPTY_OR_ERROR (celldata->xcell->value);
+       oldx = hadold ? value_get_as_float (celldata->xcell->value) : 0;
 
-int
-main ()
-{
-       GnmGoalSeekData data;
+       /* PLAN A: Newton's iterative method from initial or midpoint.  */
+       {
+               gnm_float x0;
+
+               if (hadold && oldx >= data->xmin && oldx <= data->xmax)
+                       x0 = oldx;
+               else
+                       x0 = (data->xmin + data->xmax) / 2;
+
+               status = goal_seek_newton (gnm_goal_seek_eval_cell, NULL,
+                                          data, celldata,
+                                          x0);
+               if (status == GOAL_SEEK_OK)
+                       goto DONE;
+       }
+
+       /* PLAN B: Trawl uniformly.  */
+       if (!data->havexpos || !data->havexneg) {
+               status = goal_seek_trawl_uniformly (gnm_goal_seek_eval_cell,
+                                                   data, celldata,
+                                                   data->xmin, data->xmax,
+                                                   100);
+               if (status == GOAL_SEEK_OK)
+                       goto DONE;
+       }
+
+       /* PLAN C: Trawl normally from middle.  */
+       if (!data->havexpos || !data->havexneg) {
+               gnm_float sigma, mu;
+               int i;
+
+               sigma = MIN (data->xmax - data->xmin, 1e6);
+               mu = (data->xmax + data->xmin) / 2;
+
+               for (i = 0; i < 5; i++) {
+                       sigma /= 10;
+                       status = goal_seek_trawl_normally (gnm_goal_seek_eval_cell,
+                                                          data, celldata,
+                                                          mu, sigma, 30);
+                       if (status == GOAL_SEEK_OK)
+                               goto DONE;
+               }
+       }
+
+       /* PLAN D: Trawl normally from left.  */
+       if (!data->havexpos || !data->havexneg) {
+               gnm_float sigma, mu;
+               int i;
+
+               sigma = MIN (data->xmax - data->xmin, 1e6);
+               mu = data->xmin;
+
+               for (i = 0; i < 5; i++) {
+                       sigma /= 10;
+                       status = goal_seek_trawl_normally (gnm_goal_seek_eval_cell,
+                                                          data, celldata,
+                                                          mu, sigma, 20);
+                       if (status == GOAL_SEEK_OK)
+                               goto DONE;
+               }
+       }
+
+       /* PLAN E: Trawl normally from right.  */
+       if (!data->havexpos || !data->havexneg) {
+               gnm_float sigma, mu;
+               int i;
+
+               sigma = MIN (data->xmax - data->xmin, 1e6);
+               mu = data->xmax;
+
+               for (i = 0; i < 5; i++) {
+                       sigma /= 10;
+                       status = goal_seek_trawl_normally (gnm_goal_seek_eval_cell,
+                                                          data, celldata,
+                                                          mu, sigma, 20);
+                       if (status == GOAL_SEEK_OK)
+                               goto DONE;
+               }
+       }
+
+       /* PLAN F: Newton iteration with uniform net of starting points.  */
+       if (!data->havexpos || !data->havexneg) {
+               int i;
+               const int N = 10;
 
-       goal_seek_initialize (&data);
-       data.xmin = -100;
-       data.xmax = 100;
+               for (i = 1; i <= N; i++) {
+                       gnm_float x0 =  data->xmin +
+                               (data->xmax - data->xmin) / (N + 1) * i;
 
-       goal_seek_newton (f, NULL, &data, NULL, 50.0);
+                       status = goal_seek_newton (gnm_goal_seek_eval_cell, NULL,
+                                                  data, celldata,
+                                                  x0);
+                       if (status == GOAL_SEEK_OK)
+                               goto DONE;
+               }
+       }
 
-       goal_seek_newton (f, df, &data, NULL, 50.0);
+       /* PLAN Z: Bisection.  */
+       {
+               status = goal_seek_bisection (gnm_goal_seek_eval_cell,
+                                             data, celldata);
+               if (status == GOAL_SEEK_OK)
+                       goto DONE;
+       }
 
-       return 0;
+ DONE:
+       if (status == GOAL_SEEK_OK)
+               v = value_new_float (data->root);
+       else if (hadold)
+               v = value_new_float (oldx);
+       else
+               v = value_new_empty ();
+       sheet_cell_set_value (celldata->xcell, v);
+
+       return status;
 }
-#endif
diff --git a/src/tools/goal-seek.h b/src/tools/goal-seek.h
index 9d1d8b1..0417b87 100644
--- a/src/tools/goal-seek.h
+++ b/src/tools/goal-seek.h
@@ -5,22 +5,28 @@
 #include <glib.h>
 
 typedef struct {
-       gnm_float xmin;           /* Minimum allowed value for x.  */
-       gnm_float xmax;           /* Maximum allowed value for x.  */
-       gnm_float precision;      /* Desired relative precision.  */
+       gnm_float xmin;           // Minimum allowed value for x.
+       gnm_float xmax;           // Maximum allowed value for x.
+       gnm_float precision;      // Desired relative precision.
 
-       gboolean havexpos;        /* Do we have a valid xpos?  */
-       gnm_float xpos;           /* Value for which f(xpos) > 0.  */
-       gnm_float ypos;           /* f(xpos).  */
+       gboolean havexpos;        // Do we have a valid xpos?
+       gnm_float xpos;           // Value for which f(xpos) > 0.
+       gnm_float ypos;           // f(xpos).
 
-       gboolean havexneg;        /* Do we have a valid xneg?  */
-       gnm_float xneg;           /* Value for which f(xneg) < 0.  */
-       gnm_float yneg;           /* f(xneg).  */
+       gboolean havexneg;        // Do we have a valid xneg?
+       gnm_float xneg;           // Value for which f(xneg) < 0.
+       gnm_float yneg;           // f(xneg).
 
-       gboolean have_root;       /* Do we have a valid root?  */
-       gnm_float root;           /* Value for which f(root) == 0.  */
+       gboolean have_root;       // Do we have a valid root?
+       gnm_float root;           // Value for which f(root) == 0.
 } GnmGoalSeekData;
 
+typedef struct {
+       GnmCell *xcell;           // Cell to change
+       GnmCell *ycell;           // Result cell
+       gnm_float ytarget;        // Target value
+} GnmGoalSeekCellData;
+
 typedef enum { GOAL_SEEK_OK, GOAL_SEEK_ERROR } GnmGoalSeekStatus;
 
 typedef GnmGoalSeekStatus (*GnmGoalSeekFunction) (gnm_float x, gnm_float *y, void *user_data);
@@ -28,30 +34,37 @@ typedef GnmGoalSeekStatus (*GnmGoalSeekFunction) (gnm_float x, gnm_float *y, voi
 void goal_seek_initialize (GnmGoalSeekData *data);
 
 GnmGoalSeekStatus goal_seek_point (GnmGoalSeekFunction f,
-                               GnmGoalSeekData *data,
-                               void *user_data,
-                               gnm_float x0);
+                                  GnmGoalSeekData *data,
+                                  void *user_data,
+                                  gnm_float x0);
 
 GnmGoalSeekStatus goal_seek_newton (GnmGoalSeekFunction f,
-                                GnmGoalSeekFunction df,
-                                GnmGoalSeekData *data,
-                                void *user_data,
-                                gnm_float x0);
+                                   GnmGoalSeekFunction df,
+                                   GnmGoalSeekData *data,
+                                   void *user_data,
+                                   gnm_float x0);
 
 GnmGoalSeekStatus goal_seek_bisection (GnmGoalSeekFunction f,
-                                   GnmGoalSeekData *data,
-                                   void *user_data);
+                                      GnmGoalSeekData *data,
+                                      void *user_data);
 
 GnmGoalSeekStatus goal_seek_trawl_uniformly (GnmGoalSeekFunction f,
-                                         GnmGoalSeekData *data,
-                                         void *user_data,
-                                         gnm_float xmin, gnm_float xmax,
-                                         int points);
+                                            GnmGoalSeekData *data,
+                                            void *user_data,
+                                            gnm_float xmin, gnm_float xmax,
+                                            int points);
 
 GnmGoalSeekStatus goal_seek_trawl_normally (GnmGoalSeekFunction f,
-                                        GnmGoalSeekData *data,
-                                        void *user_data,
-                                        gnm_float mu, gnm_float sigma,
-                                        int points);
+                                           GnmGoalSeekData *data,
+                                           void *user_data,
+                                           gnm_float mu, gnm_float sigma,
+                                           int points);
+
+GnmGoalSeekStatus gnm_goal_seek_eval_cell (gnm_float x,
+                                          gnm_float *y, gpointer data);
+
+GnmGoalSeekStatus gnm_goal_seek_cell (GnmGoalSeekData *data,
+                                     GnmGoalSeekCellData *celldata);
+
 
 #endif


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