GnmSolver * nlsolve_solver_factory (GnmSolverFactory *factory, GnmSolverParameters *params) { GnmSolver *res = g_object_new (GNM_SOLVER_TYPE, "params", params, NULL); GnmNlsolve *nl = g_new0 (GnmNlsolve, 1); GSList *input_cells, *l; int n; GnmValue const *vinput = gnm_solver_param_get_input (params); GnmEvalPos ep; GnmCellRef origin; nl->parent = GNM_SOLVER (res); nl->maximize = (params->problem_type == GNM_SOLVER_MAXIMIZE); eval_pos_init_sheet (&ep, params->sheet); if (vinput) { gnm_cellref_make_abs (&origin, &vinput->v_range.cell.a, &ep); nl->origin.col = origin.col; nl->origin.row = origin.row; nl->input_width = value_area_get_width (vinput, &ep); nl->input_height = value_area_get_height (vinput, &ep); } nl->debug = gnm_solver_debug (); nl->max_iter = params->options.max_iter; nl->min_factor = 1e-10; nl->target = gnm_solver_param_get_target_cell (params); nl->vars = g_ptr_array_new (); input_cells = gnm_solver_param_get_input_cells (params); for (l = input_cells; l; l = l->next) g_ptr_array_add (nl->vars, l->data); g_slist_free (input_cells); n = nl->vars->len; nl->x0 = g_new (gnm_float, n); 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_object_set_data_full (G_OBJECT (res), PRIVATE_KEY, nl, (GDestroyNotify)gnm_nlsolve_final); return res; }
GnmValue * gnm_ifs_func (GPtrArray *data, GPtrArray *crits, GnmValue const *vals, float_range_function_t fun, GnmStdError err, GnmEvalPos const *ep, CollectFlags flags) { int sx, sy, x, y; unsigned ui, N = 0, nalloc = 0; gnm_float *xs = NULL; GnmValue *res = NULL; gnm_float fres; g_return_val_if_fail (data->len == crits->len, NULL); if (flags & ~(COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS | COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_ERRORS)) { g_warning ("unsupported flags in gnm_ifs_func %x", flags); } sx = value_area_get_width (vals, ep); sy = value_area_get_height (vals, ep); for (ui = 0; ui < data->len; ui++) { GnmValue const *datai = g_ptr_array_index (data, ui); if (value_area_get_width (datai, ep) != sx || value_area_get_height (datai, ep) != sy) return value_new_error_VALUE (ep); } for (y = 0; y < sy; y++) { for (x = 0; x < sx; x++) { GnmValue const *v; gboolean match = TRUE; for (ui = 0; match && ui < crits->len; ui++) { GnmCriteria *crit = g_ptr_array_index (crits, ui); GnmValue const *datai = g_ptr_array_index (data, ui); v = value_area_get_x_y (datai, x, y, ep); match = crit->fun (v, crit); } if (!match) continue; // Match. Maybe collect the data point. v = value_area_get_x_y (vals, x, y, ep); if ((flags & COLLECT_IGNORE_STRINGS) && VALUE_IS_STRING (v)) continue; if ((flags & COLLECT_IGNORE_BOOLS) && VALUE_IS_BOOLEAN (v)) continue; if ((flags & COLLECT_IGNORE_BLANKS) && VALUE_IS_EMPTY (v)) continue; if ((flags & COLLECT_IGNORE_ERRORS) && VALUE_IS_ERROR (v)) continue; if (VALUE_IS_ERROR (v)) { res = value_dup (v); goto out; } if (N >= nalloc) { nalloc = (2 * nalloc) + 100; xs = g_renew (gnm_float, xs, nalloc); } xs[N++] = value_get_as_float (v); } } if (fun (xs, N, &fres)) { res = value_new_error_std (ep, err); } else res = value_new_float (fres); out: g_free (xs); return res; }
static gboolean analysis_tool_principal_components_engine_run (data_analysis_output_t *dao, analysis_tools_data_generic_t *info) { int l = g_slist_length (info->input), i; GSList *inputdata; GnmFunc *fd_mean; GnmFunc *fd_var; GnmFunc *fd_eigen; GnmFunc *fd_mmult; GnmFunc *fd_munit; GnmFunc *fd_sqrt; GnmFunc *fd_count; GnmFunc *fd_sum; GnmFunc *fd_and; GnmFunc *fd_if; GnmExpr const *expr; GnmExpr const *expr_count; GnmExpr const *expr_munit; GnmExpr const *expr_and; int data_points; GnmExprList *and_args = NULL; if (!dao_cell_is_visible (dao, l, 9 + 3 * l)) { dao_set_bold (dao, 0, 0, 0, 0); dao_set_italic (dao, 0, 0, 0, 0); dao_set_cell (dao, 0, 0, _("Principal components analysis has " "insufficient space.")); return 0; } fd_mean = gnm_func_lookup_or_add_placeholder ("AVERAGE", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_mean); fd_var = gnm_func_lookup_or_add_placeholder ("VAR", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_var); fd_eigen = gnm_func_lookup_or_add_placeholder ("EIGEN", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_eigen); fd_mmult = gnm_func_lookup_or_add_placeholder ("MMULT", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_mmult); fd_munit = gnm_func_lookup_or_add_placeholder ("MUNIT", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_munit); fd_sqrt = gnm_func_lookup_or_add_placeholder ("SQRT", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_sqrt); fd_count = gnm_func_lookup_or_add_placeholder ("COUNT", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_count); fd_sum = gnm_func_lookup_or_add_placeholder ("SUM", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_sum); fd_and = gnm_func_lookup_or_add_placeholder ("AND", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_and); fd_if = gnm_func_lookup_or_add_placeholder ("IF", dao->sheet ? dao->sheet->workbook : NULL, FALSE); gnm_func_ref (fd_if); dao_set_bold (dao, 0, 0, 0, 0); dao_set_italic (dao, 0, 0, 0, 11 + 3 * l); dao_set_format (dao, 0, 0, 0, 0, _("\"Principal Components Analysis\";" "[Red]\"Principal Components Analysis is invalid.\"")); dao_set_align (dao, 0, 0, 0, 0, HALIGN_LEFT, VALIGN_BOTTOM); dao->offset_row++; analysis_tool_table (dao, info, _("Covariances:"), "COVAR", TRUE); dao->offset_row--; for (i = 1, inputdata = info->input; inputdata != NULL; i++, inputdata = inputdata->next) analysis_tools_write_label (inputdata->data, dao, info, 0, 9 + 2 * l + i, i); data_points = value_area_get_width (info->input->data, NULL) * value_area_get_height (info->input->data, NULL); for (i = 0; i < l; i++) and_args = gnm_expr_list_prepend (and_args, gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (data_points)), GNM_EXPR_OP_EQUAL, make_cellref (1 + i, 3 + l))); expr_and = gnm_expr_new_funcall (fd_and, and_args); dao_set_cell_expr (dao, 0, 0, gnm_expr_new_funcall3 (fd_if, expr_and, gnm_expr_new_constant (value_new_int (1)), gnm_expr_new_constant (value_new_int (-1)))); dao_set_merge (dao,0,0,2,0); set_cell_text_col (dao, 0, 3 + l, _("/Count:" "/Mean:" "/Variance:" "//Eigenvalues:" "/Eigenvectors:")); dao_set_cell (dao, 0, 11 + 3 * l, _("Percent of Trace:")); dao_set_italic (dao, 0, 9 + 2 * l, 1 + l, 9 + 2 * l); dao_set_percent (dao, 1, 11 + 3 * l, 1 + l, 11 + 3 * l); for (i = 1, inputdata = info->input; inputdata != NULL; i++, inputdata = inputdata->next) { expr = gnm_expr_new_constant (value_dup (inputdata->data)); dao_set_cell_expr (dao, i, 3 + l, gnm_expr_new_funcall1 (fd_count, gnm_expr_copy (expr))); dao_set_cell_expr (dao, i, 4 + l, gnm_expr_new_funcall1 (fd_mean, gnm_expr_copy (expr))); dao_set_cell_expr (dao, i, 5 + l, gnm_expr_new_funcall1 (fd_var, expr)); } expr_count = gnm_expr_new_binary (make_cellref (0,-4), GNM_EXPR_OP_DIV, gnm_expr_new_binary (make_cellref (0,-4), GNM_EXPR_OP_SUB, gnm_expr_new_constant (value_new_int (1)))); expr = gnm_expr_new_funcall1 (fd_eigen, gnm_expr_new_binary (expr_count, GNM_EXPR_OP_MULT, make_rangeref (0, - (5 + l), l - 1, - 6))); dao_set_array_expr (dao, 1, 7 + l, l, l + 1, expr); for (i = 1; i <= l; i++) { dao_set_align (dao, i, 9 + 2 * l, i, 9 + 2 * l, HALIGN_CENTER, VALIGN_BOTTOM); dao_set_cell_printf (dao, i, 9 + 2 * l, "\xce\xbe%i", i); dao_set_cell_expr (dao, i, 11 + 3 * l, gnm_expr_new_binary (make_cellref (0,- 4 - 2 * l), GNM_EXPR_OP_DIV, gnm_expr_new_funcall1 (fd_sum, dao_get_rangeref (dao, 1, 7 + l, l, 7 + l)))); } expr_munit = gnm_expr_new_funcall1 (fd_munit, gnm_expr_new_constant (value_new_int (l))); expr = gnm_expr_new_funcall2 (fd_mmult, gnm_expr_new_binary (gnm_expr_new_funcall1 (fd_sqrt, gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)), GNM_EXPR_OP_DIV, make_rangeref (0, - 5 - l, l - 1, - 5 - l))), GNM_EXPR_OP_MULT, gnm_expr_copy (expr_munit)), make_rangeref (0, - 2 - l, l - 1, - 3)); expr = gnm_expr_new_funcall2 (fd_mmult, expr, gnm_expr_new_binary (gnm_expr_new_funcall1 (fd_sqrt, make_rangeref (0, - 3 - l, l - 1, - 3 - l)), GNM_EXPR_OP_MULT, expr_munit)); dao_set_array_expr (dao, 1, 10 + 2 * l, l, l, expr); gnm_func_unref (fd_mean); gnm_func_unref (fd_var); gnm_func_unref (fd_eigen); gnm_func_unref (fd_mmult); gnm_func_unref (fd_munit); gnm_func_unref (fd_sqrt); gnm_func_unref (fd_count); gnm_func_unref (fd_sum); gnm_func_unref (fd_and); gnm_func_unref (fd_if); dao_redraw_respan (dao); return 0; }
static gboolean cb_read_stdout (GIOChannel *channel, GIOCondition cond, GnmLPSolve *lp) { const char obj_line_prefix[] = "Value of objective function:"; size_t obj_line_len = sizeof (obj_line_prefix) - 1; const char val_header_line[] = "Actual values of the variables:"; size_t val_header_len = sizeof (val_header_line) - 1; do { GIOStatus status; gchar *line = NULL; gsize tpos; status = g_io_channel_read_line (channel, &line, NULL, &tpos, NULL); if (status != G_IO_STATUS_NORMAL) break; line[tpos] = 0; if (line[0] == 0 || g_ascii_isspace (line[0])) lp->section = SEC_UNKNOWN; else if (lp->section == SEC_UNKNOWN && !strncmp (line, obj_line_prefix, obj_line_len)) { GnmSolverResult *r; gnm_lpsolve_flush_solution (lp); r = gnm_lpsolve_start_solution (lp); r->quality = GNM_SOLVER_RESULT_FEASIBLE; r->value = g_ascii_strtod (line + obj_line_len, NULL); } else if (lp->section == SEC_UNKNOWN && !strncmp (line, val_header_line, val_header_len)) { lp->section = SEC_VALUES; } else if (lp->section == SEC_VALUES && lp->result) { GnmSolverResult *r = lp->result; int x, y; double v; char *space = strchr (line, ' '); GnmCell *cell; if (!space) { lp->section = SEC_UNKNOWN; continue; } *space = 0; cell = gnm_sub_solver_find_cell (lp->parent, line); if (!cell) { g_printerr ("Strange cell %s in output\n", line); lp->section = SEC_UNKNOWN; continue; } v = g_ascii_strtod (space + 1, NULL); x = cell->pos.col - lp->srinput.range.start.col; y = cell->pos.row - lp->srinput.range.start.row; if (x >= 0 && x < value_area_get_width (r->solution, NULL) && y >= 0 && y < value_area_get_height (r->solution, NULL)) value_array_set (r->solution, x, y, value_new_float (v)); } g_free (line); } while (1); return TRUE; }
static GnmValue * gnumeric_periodogram (GnmFuncEvalInfo *ei, GnmValue const * const *argv) { gnm_float *ord, *absc; int filter, interp; int n0, n1, nb; GnmValue *error = NULL; GnmValue *res; CollectFlags flags; GnmEvalPos const * const ep = ei->pos; GnmValue const * const Pt = argv[0]; int i; GSList *missing0 = NULL, *missing1 = NULL; gnm_complex *in, *out = NULL; int const cols = value_area_get_width (Pt, ep); int const rows = value_area_get_height (Pt, ep); if (cols == 1) nb=rows; else { if (rows == 1) nb=cols; else nb=0; } if (nb == 0) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } flags=COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS; ord = collect_floats_value_with_info (argv[0], ei->pos, flags, &n0, &missing0, &error); if (error) { g_slist_free (missing0); return error; } if (n0 == 0) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } if (argv[1]) { filter = (int) gnm_floor (value_get_as_float (argv[1])); if (filter < 0 || filter > FILTER_WELCH) { g_slist_free (missing0); g_free (ord); res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } } else filter = FILTER_NONE; if (argv[2]) { gnm_float *interpolated, *new_ord, start, incr; int n2; INTERPPROC(interpproc) = NULL; absc = collect_floats_value_with_info (argv[2], ei->pos, flags, &n1, &missing1, &error); if (n1 == 1) { g_slist_free (missing1); g_free (absc); goto no_absc; } if (error) { g_slist_free (missing0); g_slist_free (missing1); g_free (absc); return error; } if (n1 == 0) { g_slist_free (missing0); g_slist_free (missing1); g_free (absc); g_free (ord); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } if (argv[3]) { interp = (int) gnm_floor (value_get_as_float (argv[3])); if (interp < 0 || interp > INTERPOLATION_SPLINE_AVG) { g_slist_free (missing0); g_slist_free (missing1); g_free (absc); g_free (ord); return error; } } else interp = INTERPOLATION_LINEAR; if (missing0 || missing1) { GSList *missing = gnm_slist_sort_merge (missing0, missing1); gnm_strip_missing (ord, &n0, missing); gnm_strip_missing (absc, &n1, missing); g_slist_free (missing); if (n0 != n1) g_warning ("This should not happen. n0=%d n1=%d\n", n0, n1); } n0 = n1 = MIN (n0, n1); /* here we test if there is abscissas are always increasing, if not, an error is returned */ if (n0 < 2 || !gnm_range_increasing (absc, n0) || n0 == 0) { g_free (absc); g_free (ord); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } if (argv[4]) { n1 = (int) gnm_floor (value_get_as_float (argv[4])); if (n1 < n0) { g_free (absc); g_free (ord); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } nb = 1; while (nb < n1) nb *= 2; } else { n1 = 1; while (n1 < n0) n1 *= 2; nb = n1; } incr = (absc[n0 - 1] - absc[0]) / n1; switch (interp) { case INTERPOLATION_LINEAR: interpproc = linear_interpolation; start = absc[0]; n2 = n1; break; case INTERPOLATION_LINEAR_AVG: interpproc = linear_averaging; start = absc[0] - incr / 2.; n2 = n1 + 1; break; case INTERPOLATION_STAIRCASE: interpproc = staircase_interpolation; start = absc[0]; n2 = n1; break; case INTERPOLATION_STAIRCASE_AVG: interpproc = staircase_averaging; start = absc[0] - incr / 2.; n2 = n1 + 1; break; case INTERPOLATION_SPLINE: interpproc = spline_interpolation; start = absc[0]; n2 = n1; break; case INTERPOLATION_SPLINE_AVG: interpproc = spline_averaging; start = absc[0] - incr / 2.; n2 = n1 + 1; break; default: g_free (absc); g_free (ord); return value_new_error_std (ei->pos, GNM_ERROR_NA); } interpolated = g_new (gnm_float, n1); for (i = 0; i < n2; i++) interpolated[i] = start + i * incr; new_ord = interpproc (absc, ord, n0, interpolated, n1); g_free (ord); ord = new_ord; if (ord == NULL) { g_free (absc); g_free (interpolated); return value_new_error_std (ei->pos, GNM_ERROR_NA); } n0 = n1; } else { no_absc: /* we have no interpolation to apply, so just take the values */ if (missing0) { gnm_strip_missing (ord, &n0, missing0); g_slist_free (missing0); } nb = 1; while (nb < n0) nb *= 2; } /* Now apply the filter if any */ if (filter != FILTER_NONE) { gnm_float factor; switch (filter) { case FILTER_BARTLETT: factor = n0 / 2.; for (i = 0; i < n0; i++) ord[i] *= 1. - gnm_abs ((i / factor - 1)); break; case FILTER_HANN: factor = 2. * M_PIgnum / n0; for (i = 0; i < n0; i++) ord[i] *= 0.5 * (1 - gnm_cos (factor * i)); break; case FILTER_WELCH: factor = n0 / 2.; for (i = 0; i < n0; i++) ord[i] *= 1. - (i / factor - 1.) * (i / factor - 1.); break; } } /* Transform and return the result */ in = g_new0 (gnm_complex, nb); for (i = 0; i < n0; i++){ in[i].re = ord[i]; } g_free (ord); gnm_fourier_fft (in, nb, 1, &out, FALSE); g_free (in); nb /= 2; if (out && nb > 0) { res = value_new_array_non_init (1 , nb); res->v_array.vals[0] = g_new (GnmValue *, nb); for (i = 0; i < nb; i++) res->v_array.vals[0][i] = value_new_float (gnm_sqrt ( out[i].re * out[i].re + out[i].im * out[i].im)); g_free (out); } else
static GnmValue * gnumeric_interpolation (GnmFuncEvalInfo *ei, GnmValue const * const *argv) { gnm_float *vals0, *vals1, *vals2, *fres; int n0, n2; int interp; GnmValue *error = NULL; GnmValue *res; CollectFlags flags; GnmEvalPos const * const ep = ei->pos; GnmValue const * const PtInterpolation = argv[2]; int r, i; GSList *missing2 = NULL, *missing; INTERPPROC interpproc = NULL; gboolean constp = FALSE; /* argv[2] */ int const cols = value_area_get_width (PtInterpolation, ep); int const rows = value_area_get_height (PtInterpolation, ep); if (rows == 0 || cols != 1) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } flags = COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS | COLLECT_IGNORE_ERRORS; vals2 = collect_floats_value_with_info (PtInterpolation, ei->pos, flags, &n2, &missing2, &error); if (error) { g_slist_free (missing2); return error; } /* argv[3] */ if (argv[3]) { interp = (int) gnm_floor (value_get_as_float (argv[3])); if (interp < 0 || interp > INTERPOLATION_SPLINE_AVG) { g_slist_free (missing2); g_free (vals2); return value_new_error_VALUE (ei->pos); } } else interp = INTERPOLATION_LINEAR; switch (interp) { case INTERPOLATION_LINEAR: interpproc = linear_interpolation; break; case INTERPOLATION_LINEAR_AVG: interpproc = linear_averaging; n2--; break; case INTERPOLATION_STAIRCASE: interpproc = staircase_interpolation; break; case INTERPOLATION_STAIRCASE_AVG: interpproc = staircase_averaging; n2--; break; case INTERPOLATION_SPLINE: interpproc = spline_interpolation; break; case INTERPOLATION_SPLINE_AVG: interpproc = spline_averaging; n2--; break; } if (n2 <= 0) { g_slist_free (missing2); g_free (vals2); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } /* argv[0] & argv[1] */ flags = COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS; error = collect_float_pairs (argv[0], argv[1], ei->pos, flags, &vals0, &vals1, &n0, &constp); if (error) { g_slist_free (missing2); g_free (vals2); return error; } /* Check whether the abscissae are increasing, if not order them */ if (!gnm_range_increasing (vals0, n0)) { gboolean switched = TRUE; if (constp) { vals0 = g_memdup (vals0, sizeof(gnm_float) * n0); vals1 = g_memdup (vals1, sizeof(gnm_float) * n0); constp = FALSE; } while (switched) { gnm_float *val; switched = FALSE; for (i = 1, val = vals0; i < n0; i++, val++) { if (*val == *(val + 1)) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE) ; goto done; } if (*val > *(val + 1)) { gnm_float v = *val; *val = *(val + 1); *(val + 1) = v; v = *(vals1 + i); *(vals1 + i) = *(vals1 + i - 1); *(vals1 + i - 1) = v; switched = TRUE; } } } } { int n = n2; if (missing2) gnm_strip_missing (vals2, &n, missing2); res = value_new_array_non_init (1 , n2); i = 0; res->v_array.vals[0] = g_new (GnmValue *, n2); fres = interpproc (vals0, vals1, n0, vals2, n); missing = missing2; if (fres) { i = 0; for (r = 0 ; r < n2; ++r) if (missing && r == GPOINTER_TO_INT (missing->data)) { missing = missing->next; res->v_array.vals[0][r] = value_new_error_std (ei->pos, GNM_ERROR_VALUE); } else res->v_array.vals[0][r] = value_new_float (fres[i++]); g_free (fres); } else { for( r = 0 ; r < n2; ++r) res->v_array.vals[0][r] = value_new_error_std (ei->pos, GNM_ERROR_VALUE); } } done: g_slist_free (missing2); if (!constp) { g_free (vals0); g_free (vals1); } g_free (vals2); return res; }