Alien-libhisto
view release on metacpan or search on metacpan
bundled/tools/src/cmd_fit.c view on Meta::CPAN
fprintf(out, "}\n");
}
#include "cli_opt.h"
typedef struct {
double lower_bounds[16];
double upper_bounds[16];
bool fixed_params[16];
bool has_lower;
bool has_upper;
bool has_fixed;
double range_min;
double range_max;
} fit_bounds_ctx_t;
static int cb_parse_bounds(const char *opt_name, const char *val, void *data, char *err_buf, size_t err_size) {
(void)opt_name;
fit_bounds_ctx_t *ctx = (fit_bounds_ctx_t *)data;
int pidx = 0;
double bmin = 0.0, bmax = 0.0;
if (!val || sscanf(val, "%d=%lf:%lf", &pidx, &bmin, &bmax) != 3 || pidx < 0 || pidx >= 16) {
snprintf(err_buf, err_size, "Bounds must be in IDX=MIN:MAX format (e.g. --bounds=2=0.1:10.0)");
return 1;
}
ctx->lower_bounds[pidx] = bmin;
ctx->upper_bounds[pidx] = bmax;
ctx->has_lower = true;
ctx->has_upper = true;
return 0;
}
static int cb_parse_fix_param(const char *opt_name, const char *val, void *data, char *err_buf, size_t err_size) {
(void)opt_name;
fit_bounds_ctx_t *ctx = (fit_bounds_ctx_t *)data;
int pidx = 0;
double fval = 0.0;
if (!val || sscanf(val, "%d=%lf", &pidx, &fval) != 2 || pidx < 0 || pidx >= 16) {
snprintf(err_buf, err_size, "Fix-param must be in IDX=VAL format (e.g. --fix-param=1=0.0)");
return 1;
}
ctx->lower_bounds[pidx] = fval;
ctx->upper_bounds[pidx] = fval;
ctx->fixed_params[pidx] = true;
ctx->has_fixed = true;
return 0;
}
static int cb_parse_range(const char *opt_name, const char *val, void *data, char *err_buf, size_t err_size) {
(void)opt_name;
fit_bounds_ctx_t *ctx = (fit_bounds_ctx_t *)data;
if (!val || sscanf(val, "%lf:%lf", &ctx->range_min, &ctx->range_max) != 2) {
snprintf(err_buf, err_size, "Range must be in MIN:MAX format (e.g. --range=0:100)");
return 1;
}
return 0;
}
int histo_cli_fit(int argc, char **argv, FILE *out, FILE *err) {
if (!out) out = stdout;
if (!err) err = stderr;
const char *model_str = "gaussian";
uint32_t poly_degree = 1;
bool use_mle = false;
bool use_unweighted = false;
double confidence = 0.95;
bool do_json = false;
bool do_quiet = false;
bool do_plot = false;
const char *input_file = NULL;
fit_bounds_ctx_t bctx;
memset(&bctx, 0, sizeof(bctx));
for (int i = 0; i < 16; ++i) {
bctx.lower_bounds[i] = -INFINITY;
bctx.upper_bounds[i] = INFINITY;
}
const cli_opt_spec_t specs[] = {
{'m', "model", NULL, CLI_OPT_TYPE_STRING, &model_str, NULL, 0, "TYPE",
"Model: gaussian (default), exponential, polynomial, breit-wigner, power-law, lognormal, gauss+linear, weibull, gamma, poisson, laplace", "gaussian"},
{'d', "degree", NULL, CLI_OPT_TYPE_UINT32, &poly_degree, NULL, 0, "N",
"Degree for polynomial model (default: 1, range: 0..10)", "1"},
{0, "mle", NULL, CLI_OPT_TYPE_BOOL, &use_mle, NULL, 0, NULL,
"Use Poisson Maximum Likelihood Estimation instead of Chi-Square", NULL},
{0, "unweighted", NULL, CLI_OPT_TYPE_BOOL, &use_unweighted, NULL, 0, NULL,
"Use Unweighted Least Squares", NULL},
{'b', "bounds", NULL, CLI_OPT_TYPE_CALLBACK, &bctx, cb_parse_bounds, 0, "IDX=MIN:MAX",
"Set parameter lower and upper bounds (e.g. --bounds=2=0.1:10.0)", NULL},
{'f', "fix-param", NULL, CLI_OPT_TYPE_CALLBACK, &bctx, cb_parse_fix_param, 0, "IDX=VAL",
"Freeze parameter to constant value (e.g. --fix-param=1=0.0)", NULL},
{0, "range", NULL, CLI_OPT_TYPE_CALLBACK, &bctx, cb_parse_range, 0, "MIN:MAX",
"Sub-range window for fitting [MIN, MAX]", NULL},
{'c', "confidence", NULL, CLI_OPT_TYPE_DOUBLE, &confidence, NULL, 0, "LEV",
"Confidence interval level (default: 0.95)", "0.95"},
{'j', "json", NULL, CLI_OPT_TYPE_BOOL, &do_json, NULL, 0, NULL,
"Emit structured JSON fit results", NULL},
{'q', "quiet", NULL, CLI_OPT_TYPE_BOOL, &do_quiet, NULL, 0, NULL,
"Output only optimal parameter values (tab-separated)", NULL},
{'p', "plot", NULL, CLI_OPT_TYPE_BOOL, &do_plot, NULL, 0, NULL,
"Render optional ASCII curve overlay above parameter table", NULL},
{'i', "input", NULL, CLI_OPT_TYPE_STRING, &input_file, NULL, 0, "FILE",
"Input histogram or raw sample stream file (default: stdin)", NULL}
};
cli_opt_parser_t parser;
cli_opt_init(&parser, specs, sizeof(specs) / sizeof(specs[0]),
"histo-fit", "[OPTIONS] [HISTOGRAM_FILE...]",
"Fits parametric models to 1D histograms using non-linear least squares / Poisson MLE.");
int rc = cli_opt_parse(&parser, argc, argv, 1);
if (rc < 0) {
cli_opt_print_help(&parser, out);
cli_opt_free(&parser);
return 0;
}
if (rc > 0) {
fprintf(err, "%s\n", cli_opt_error(&parser));
cli_opt_free(&parser);
return 1;
( run in 0.880 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )