Commit a14bd8de authored by Andreas J. Guelzow's avatar Andreas J. Guelzow Committed by Andreas J. Guelzow

make undoable

2002-04-05  Andreas J. Guelzow <aguelzow@taliesin.ca>

	* dialog-random-generator.c : make undoable

2002-04-05  Andreas J. Guelzow <aguelzow@taliesin.ca>

	* random-generator.[ch] : make undoable
parent 3575f4a1
...@@ -53,7 +53,6 @@ Long term breakage ...@@ -53,7 +53,6 @@ Long term breakage
- Duplicate sheet. - Duplicate sheet.
- Remove sheet. This raises some serious design issues. - Remove sheet. This raises some serious design issues.
- Freeze panes. - Freeze panes.
- Random Generator Tool.
- Goal seek. - Goal seek.
- Tabulate. - Tabulate.
......
...@@ -9,6 +9,7 @@ Andreas: ...@@ -9,6 +9,7 @@ Andreas:
* Plug leaks. * Plug leaks.
* Add preference dialog. * Add preference dialog.
* Improve treeview cell renderers. * Improve treeview cell renderers.
* Make Random Generator Tool undoable.
Jody: Jody:
* Add password dialog to support encrypted input. * Add password dialog to support encrypted input.
......
2002-04-05 Andreas J. Guelzow <aguelzow@taliesin.ca>
* dialog-random-generator.c : make undoable
2002-04-03 Andreas J. Guelzow <aguelzow@taliesin.ca> 2002-04-03 Andreas J. Guelzow <aguelzow@taliesin.ca>
* dialog-cell-sort.c : use setup_range_from_value * dialog-cell-sort.c : use setup_range_from_value
......
...@@ -362,92 +362,74 @@ dialog_random_realized (GtkWidget *widget, RandomToolState *state) ...@@ -362,92 +362,74 @@ dialog_random_realized (GtkWidget *widget, RandomToolState *state)
static void static void
random_tool_ok_clicked_cb (GtkWidget *button, RandomToolState *state) random_tool_ok_clicked_cb (GtkWidget *button, RandomToolState *state)
{ {
data_analysis_output_t *dao;
tools_data_random_t *data;
data_analysis_output_t dao; gint err;
char *text;
gint vars, count, err;
random_tool_t param;
if (state->base.warning_dialog != NULL) data = g_new0 (tools_data_random_t, 1);
gtk_widget_destroy (state->base.warning_dialog); dao = parse_output ((GenericToolState *)state, NULL);
parse_output ((GenericToolState *)state, &dao); data->wbcg = state->base.wbcg;
err = entry_to_int (GTK_ENTRY (state->vars_entry), &vars, FALSE); err = entry_to_int (GTK_ENTRY (state->vars_entry), &data->n_vars, FALSE);
err = entry_to_int (GTK_ENTRY (state->count_entry), &count, FALSE); err = entry_to_int (GTK_ENTRY (state->count_entry), &data->count, FALSE);
state->distribution = combo_get_distribution (state->distribution_combo); data->distribution = state->distribution =
combo_get_distribution (state->distribution_combo);
switch (state->distribution) { switch (state->distribution) {
case NormalDistribution: case NormalDistribution:
err = entry_to_float (GTK_ENTRY (state->par1_entry), &param.normal.mean, TRUE); err = entry_to_float (GTK_ENTRY (state->par1_entry),
err = entry_to_float (GTK_ENTRY (state->par2_entry), &param.normal.stdev, TRUE); &data->param.normal.mean, TRUE);
err = entry_to_float (GTK_ENTRY (state->par2_entry),
&data->param.normal.stdev, TRUE);
break; break;
case BernoulliDistribution: case BernoulliDistribution:
err = entry_to_float (GTK_ENTRY (state->par1_entry), &param.bernoulli.p, TRUE); err = entry_to_float (GTK_ENTRY (state->par1_entry),
&data->param.bernoulli.p, TRUE);
break; break;
case PoissonDistribution: case PoissonDistribution:
err = entry_to_float (GTK_ENTRY (state->par1_entry), &param.poisson.lambda, TRUE); err = entry_to_float (GTK_ENTRY (state->par1_entry),
&data->param.poisson.lambda, TRUE);
break; break;
case ExponentialDistribution: case ExponentialDistribution:
err = entry_to_float (GTK_ENTRY (state->par1_entry), &param.exponential.b, TRUE); err = entry_to_float (GTK_ENTRY (state->par1_entry),
&data->param.exponential.b, TRUE);
break; break;
case BinomialDistribution: case BinomialDistribution:
err = entry_to_float (GTK_ENTRY (state->par1_entry), &param.binomial.p, TRUE); err = entry_to_float (GTK_ENTRY (state->par1_entry),
err = entry_to_int (GTK_ENTRY (state->par2_entry), &param.binomial.trials, TRUE); &data->param.binomial.p, TRUE);
err = entry_to_int (GTK_ENTRY (state->par2_entry),
&data->param.binomial.trials, TRUE);
break; break;
case NegativeBinomialDistribution: case NegativeBinomialDistribution:
err = entry_to_float (GTK_ENTRY (state->par1_entry), &param.negbinom.p, TRUE); err = entry_to_float (GTK_ENTRY (state->par1_entry),
err = entry_to_int (GTK_ENTRY (state->par2_entry), &param.negbinom.f, TRUE); &data->param.negbinom.p, TRUE);
err = entry_to_int (GTK_ENTRY (state->par2_entry),
&data->param.negbinom.f, TRUE);
break; break;
case DiscreteDistribution: case DiscreteDistribution:
param.discrete.range = gnm_expr_entry_parse_as_value ( data->param.discrete.range = gnm_expr_entry_parse_as_value (
GNUMERIC_EXPR_ENTRY (state->par1_expr_entry), state->base.sheet); GNUMERIC_EXPR_ENTRY (state->par1_expr_entry), state->base.sheet);
break; break;
case UniformDistribution: case UniformDistribution:
default: default:
err = entry_to_float (GTK_ENTRY (state->par1_entry), err = entry_to_float (GTK_ENTRY (state->par1_entry),
&param.uniform.lower_limit, TRUE); &data->param.uniform.lower_limit, TRUE);
err = entry_to_float (GTK_ENTRY (state->par2_entry), err = entry_to_float (GTK_ENTRY (state->par2_entry),
&param.uniform.upper_limit, TRUE); &data->param.uniform.upper_limit, TRUE);
break; break;
} }
err = random_tool (WORKBOOK_CONTROL (state->base.wbcg), state->base.sheet, if (!cmd_analysis_tool (WORKBOOK_CONTROL (state->base.wbcg), state->base.sheet,
vars, count, state->distribution, &param,&dao); dao, data, tool_random_engine) &&
switch (err) { (button == state->base.ok_button)) {
case 0: if (state->distribution_accel) {
if (button == state->base.ok_button) { gtk_window_remove_accel_group (GTK_WINDOW (state->base.dialog),
if (state->distribution_accel) { state->distribution_accel);
gtk_window_remove_accel_group (GTK_WINDOW (state->base.dialog), state->distribution_accel = NULL;
state->distribution_accel);
state->distribution_accel = NULL;
}
gtk_widget_destroy (state->base.dialog);
} }
break; gtk_widget_destroy (state->base.dialog);
case 1: /* non-numeric probability (DiscreteDistribution) */
error_in_entry ((GenericToolState *) state, GTK_WIDGET (state->par1_expr_entry),
_("The probability input range contains a non-numeric value.\n"
"All probabilities must be non-negative numbers."));
break;
case 2: /* probabilities are all zero (DiscreteDistribution) */
error_in_entry ((GenericToolState *) state, GTK_WIDGET (state->par1_expr_entry),
_("The probabilities may not all be 0!"));
break;
case 3: /* negative probability (DiscreteDistribution) */
error_in_entry ((GenericToolState *) state, GTK_WIDGET (state->par1_expr_entry),
_("The probability input range contains a negative number.\n"
"All probabilities must be non-negative!"));
break;
case 4: /* value is empty (DiscreteDistribution) */
error_in_entry ((GenericToolState *) state, GTK_WIDGET (state->par1_expr_entry),
_("None of the values in the value range may be empty!"));
break;
default:
text = g_strdup_printf (_("An unexpected error has occurred: %d."), err);
gnumeric_notice (state->base.wbcg, GTK_MESSAGE_ERROR, text);
g_free (text);
break;
} }
return; return;
} }
......
2002-04-05 Andreas J. Guelzow <aguelzow@taliesin.ca>
* random-generator.[ch] : make undoable
2002-03-31 Andreas J. Guelzow <aguelzow@taliesin.ca> 2002-03-31 Andreas J. Guelzow <aguelzow@taliesin.ca>
* analysis-tools.c : adjust includes * analysis-tools.c : adjust includes
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
* Andreas J. Guelzow <aguelzow@taliesin.ca> * Andreas J. Guelzow <aguelzow@taliesin.ca>
* *
* (C) Copyright 2000, 2001 by Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi> * (C) Copyright 2000, 2001 by Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
* (C) Copyright 2002 by Andreas J. Guelzow <aguelzow@taliesin.ca>
* *
* Modified 2001 to use range_* functions of mathfunc.h
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "sheet-style.h" #include "sheet-style.h"
#include "workbook.h" #include "workbook.h"
#include "format.h" #include "format.h"
#include "gui-util.h"
#include "sheet-object-cell-comment.h" #include "sheet-object-cell-comment.h"
#include <libgnome/gnome-i18n.h> #include <libgnome/gnome-i18n.h>
...@@ -55,194 +56,294 @@ ...@@ -55,194 +56,294 @@
* *
**/ **/
int typedef struct {
random_tool (WorkbookControl *wbc, Sheet *sheet, int vars, int count, gint n;
random_distribution_t distribution, Value **values;
random_tool_t *param, data_analysis_output_t *dao) gnum_float *cumul_p;
} discrete_random_tool_local_t;
static void
tool_random_engine_run_discrete_clear_continuity (discrete_random_tool_local_t **continuity)
{ {
if (distribution != DiscreteDistribution) discrete_random_tool_local_t *data = *continuity;
dao_prepare_output (wbc, dao, _("Random")); gint i;
switch (distribution) {
case DiscreteDistribution: {
Value *range = param->discrete.range;
int n = range->v_range.cell.b.row - range->v_range.cell.a.row + 1;
gnum_float *prob = g_new (gnum_float, n);
gnum_float *cumul_p = g_new (gnum_float, n);
Value **values = g_new0 (Value *, n);
gnum_float cumprob = 0;
int j = 0;
int i;
int err = 0;
for (i = range->v_range.cell.a.row;
i <= range->v_range.cell.b.row;
i++, j++) {
Value *v;
gnum_float thisprob;
Cell *cell = sheet_cell_get (range->v_range.cell.a.sheet,
range->v_range.cell.a.col + 1, i);
if (cell == NULL ||
(v = cell->value) == NULL ||
!VALUE_IS_NUMBER (v)) {
err = 1;
goto random_tool_discrete_out;
}
if ((thisprob = value_get_as_float (v)) < 0) {
err = 3;
goto random_tool_discrete_out;
}
prob[j] = thisprob; for (i = 0; i < data->n; i++)
cumprob += thisprob; if (data->values[i])
cumul_p[j] = cumprob; value_release (data->values[i]);
g_free (data->cumul_p);
g_free (data->values);
g_free (data);
*continuity = NULL;
}
cell = sheet_cell_get (range->v_range.cell.a.sheet, static gboolean
range->v_range.cell.a.col, i); tool_random_engine_run_discrete_last_check (data_analysis_output_t *dao,
tools_data_random_t *info,
discrete_random_tool_t *param,
discrete_random_tool_local_t **continuity)
{
discrete_random_tool_local_t *data;
Value *range = param->range;
gnum_float cumprob = 0;
int j = 0;
int i;
if (cell == NULL || cell->value == NULL) { data = *continuity = g_new0 (discrete_random_tool_local_t, 1);
err = 4; data->n = range->v_range.cell.b.row - range->v_range.cell.a.row + 1;
goto random_tool_discrete_out; data->cumul_p = g_new (gnum_float, data->n);
} data->values = g_new0 (Value *, data->n);
values[j] = value_duplicate (cell->value); for (i = range->v_range.cell.a.row;
i <= range->v_range.cell.b.row;
i++, j++) {
Value *v;
gnum_float thisprob;
Cell *cell = sheet_cell_get (range->v_range.cell.a.sheet,
range->v_range.cell.a.col + 1, i);
if (cell == NULL ||
(v = cell->value) == NULL ||
!VALUE_IS_NUMBER (v)) {
gnumeric_notice (info->wbcg, GTK_MESSAGE_ERROR,
_("The probability input range contains a "
"non-numeric value.\n"
"All probabilities must be non-negative numbers."));
goto random_tool_discrete_out;
} }
if ((thisprob = value_get_as_float (v)) < 0) {
if (cumprob == 0) { gnumeric_notice (info->wbcg, GTK_MESSAGE_ERROR,
err = 2; _("The probability input range contains "
"a negative number.\n"
"All probabilities must be non-negative!"));
goto random_tool_discrete_out;
}
cumprob += thisprob;
data->cumul_p[j] = cumprob;
cell = sheet_cell_get (range->v_range.cell.a.sheet,
range->v_range.cell.a.col, i);
if (cell == NULL || cell->value == NULL) {
gnumeric_notice (info->wbcg, GTK_MESSAGE_ERROR,
_("None of the values in the value "
"range may be empty!"));
goto random_tool_discrete_out; goto random_tool_discrete_out;
} }
data->values[j] = value_duplicate (cell->value);
}
if (cumprob != 0) {
/* Rescale... */ /* Rescale... */
for (i = 0; i < n; i++) { for (i = 0; i < data->n; i++) {
prob[i] /= cumprob; data->cumul_p[i] /= cumprob;
cumul_p[i] /= cumprob;
} }
return FALSE;
}
gnumeric_notice (info->wbcg, GTK_MESSAGE_ERROR,
_("The probabilities may not all be 0!"));
dao_prepare_output (wbc, dao, _("Random")); random_tool_discrete_out:
for (i = 0; i < vars; i++) { tool_random_engine_run_discrete_clear_continuity (continuity);
int k; return TRUE;
for (k = 0; k < count; k++) { }
int j;
gnum_float x = random_01 ();
for (j = 0; cumul_p[j] < x; j++) static gboolean
; tool_random_engine_run_discrete (data_analysis_output_t *dao,
tools_data_random_t *info,
discrete_random_tool_t *param,
discrete_random_tool_local_t **continuity)
{
gint i;
discrete_random_tool_local_t *data = *continuity;
dao_set_cell_value (dao, i, k, value_duplicate (values[j])); for (i = 0; i < info->n_vars; i++) {
} int k;
for (k = 0; k < info->count; k++) {
int j;
gnum_float x = random_01 ();
for (j = 0; data->cumul_p[j] < x; j++)
;
dao_set_cell_value (dao, i, k, value_duplicate (data->values[j]));
} }
random_tool_discrete_out:
for (i = 0; i < n; i++)
if (values[i])
value_release (values[i]);
g_free (prob);
g_free (cumul_p);
g_free (values);
value_release (range);
if (err)
return err;
break;
} }
tool_random_engine_run_discrete_clear_continuity (continuity);
return FALSE;
}
case NormalDistribution: { static gboolean
int i, n; tool_random_engine_run_uniform (data_analysis_output_t *dao,
for (i = 0; i < vars; i++) { tools_data_random_t *info,
for (n = 0; n < count; n++) { uniform_random_tool_t *param)
gnum_float v; {
v = param->normal.stdev * random_normal () + param->normal.mean; int i, n;
dao_set_cell_float (dao, i, n, v); gnum_float range = param->upper_limit - param->lower_limit;
} for (i = 0; i < info->n_vars; i++) {
for (n = 0; n < info->count; n++) {
gnum_float v;
v = range * random_01 () + param->lower_limit;
dao_set_cell_float (dao, i, n, v);
} }
break;
} }
return FALSE;
}
case BernoulliDistribution: { static gboolean
int i, n; tool_random_engine_run_normal (data_analysis_output_t *dao,
for (i = 0; i < vars; i++) { tools_data_random_t *info,
for (n = 0; n < count; n++) { normal_random_tool_t *param)
gnum_float tmp = random_bernoulli (param->bernoulli.p); {
dao_set_cell_int (dao, i, n, (int)tmp); int i, n;
} for (i = 0; i < info->n_vars; i++) {
for (n = 0; n < info->count; n++) {
gnum_float v;
v = param->stdev * random_normal () + param->mean;
dao_set_cell_float (dao, i, n, v);
} }
break;
} }
return FALSE;
}
case UniformDistribution: { static gboolean
int i, n; tool_random_engine_run_bernoulli (data_analysis_output_t *dao,
gnum_float range = param->uniform.upper_limit - param->uniform.lower_limit; tools_data_random_t *info,
for (i = 0; i < vars; i++) { bernoulli_random_tool_t *param)
for (n = 0; n < count; n++) { {
gnum_float v; int i, n;
v = range * random_01 () + param->uniform.lower_limit; for (i = 0; i < info->n_vars; i++) {
dao_set_cell_float (dao, i, n, v); for (n = 0; n < info->count; n++) {
gnum_float tmp = random_bernoulli (param->p);
dao_set_cell_int (dao, i, n, (int)tmp);
} }
}
break;
} }
return FALSE;
}
case PoissonDistribution: { static gboolean
int i, n; tool_random_engine_run_binomial (data_analysis_output_t *dao,
for (i = 0; i < vars; i++) { tools_data_random_t *info,
for (n = 0; n < count; n++) { binomial_random_tool_t *param)
gnum_float v; {
v = random_poisson (param->poisson.lambda); int i, n;
dao_set_cell_float (dao, i, n, v); for (i = 0; i < info->n_vars; i++) {
} for (n = 0; n < info->count; n++) {
gnum_float v;
v = random_binomial (param->p,
param->trials);
dao_set_cell_float (dao, i, n, v);
} }
break; }
} return FALSE;
}
case ExponentialDistribution: { static gboolean
int i, n; tool_random_engine_run_negbinom (data_analysis_output_t *dao,
for (i = 0; i < vars; i++) { tools_data_random_t *info,
for (n = 0; n < count; n++) { negbinom_random_tool_t *param)
gnum_float v; {
v = random_exponential (param->exponential.b); int i, n;
dao_set_cell_float (dao, i, n, v); for (i = 0; i < info->n_vars; i++) {
} for (n = 0; n < info->count; n++) {
gnum_float v;
v = random_negbinom (param->p,
param->f);
dao_set_cell_float (dao, i, n, v);
} }
break;
} }
return FALSE;
}
case BinomialDistribution: { static gboolean
int i, n; tool_random_engine_run_poisson (data_analysis_output_t *dao,
for (i = 0; i < vars; i++) { tools_data_random_t *info,
for (n = 0; n < count; n++) { poisson_random_tool_t *param)
gnum_float v; {
v = random_binomial (param->binomial.p, int i, n;
param->binomial.trials); for (i = 0; i < info->n_vars; i++) {
dao_set_cell_float (dao, i, n, v); for (n = 0; n < info->count; n++) {
} gnum_float v;
v = random_poisson (param->lambda);
dao_set_cell_float (dao, i, n, v);
} }
break;
} }
return FALSE;
}
case NegativeBinomialDistribution: { static gboolean
int i, n; tool_random_engine_run_exponential (data_analysis_output_t *dao,
for (i = 0; i < vars; i++) { tools_data_random_t *info,
for (n = 0; n < count; n++) { exponential_random_tool_t *param)
gnum_float v; {
v = random_negbinom (param->negbinom.p, int i, n;
param->negbinom.f); for (i = 0; i < info->n_vars; i++) {
dao_set_cell_float (dao, i, n, v); for (n = 0; n < info->count; n++) {
} gnum_float v;
v = random_exponential (param->b);
dao_set_cell_float (dao, i, n, v);
} }
break; }
} return FALSE;
}
gboolean
tool_random_engine (data_analysis_output_t