[gnumeric] GoalSeek: code cleanup.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] GoalSeek: code cleanup.
- Date: Fri, 18 May 2018 12:51:18 +0000 (UTC)
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]