#include #include #include #include "gsl/gsl_vector.h" #include "gsl/gsl_multiroots.h" #include "gsl/gsl_permutation.h" #include "gsl/gsl_linalg.h" /* #undef USE_DERIVATIVES */ /* #define SOLVER gsl_multiroot_fsolver_hybrids */ /* #define SOLVER gsl_multiroot_fsolver_hybrid */ /* #define SOLVER gsl_multiroot_fsolver_dnewton */ #define USE_DERIVATIVES /* #define SOLVER gsl_multiroot_fdfsolver_hybridsj */ /* #define SOLVER gsl_multiroot_fdfsolver_hybridj */ /* #define SOLVER gsl_multiroot_fdfsolver_newton */ #define SOLVER gsl_multiroot_fdfsolver_gnewton #define CONSTANT INT_MAX /** * trigrid_data -- parameters and results for a triangular grid fitting */ struct trigrid_data { /* parameters */ unsigned int X, Y; double * A; /* results */ int status; unsigned int iter; #ifdef USE_DERIVATIVES gsl_multiroot_fdfsolver * s; #else gsl_multiroot_fsolver * s; #endif unsigned int xs_start, ys_start; gsl_vector * xs; }; void trigrid_fit(struct trigrid_data * data); int trigrid_f(const gsl_vector * xs, void * params, gsl_vector * f); int trigrid_df(const gsl_vector * xs, void * params, gsl_matrix * J); int trigrid_fdf(const gsl_vector * xs, void * params, gsl_vector * f, gsl_matrix * J); double trigrid_get_x(const struct trigrid_data * data, const gsl_vector * xs, unsigned int x, unsigned int y); double trigrid_get_y(const struct trigrid_data * data, const gsl_vector * xs, unsigned int x, unsigned int y); unsigned int trigrid_offset_x(const struct trigrid_data * data, unsigned int x, unsigned int y); unsigned int trigrid_offset_y(const struct trigrid_data * data, unsigned int x, unsigned int y); int main(void); void trigrid_print(struct trigrid_data * data); /** * trigrid_fit -- create a triangular grid with triangle areas A * * p struct trigrid_data with the following fields filled in: * X number of pairs of triangles in a row * Y number of rows of triangles * A target areas from bottom left by row, 2 * X * Y values * * p is updated with the result, which can be conveniently accessed * using trigrid_get_x and trigrid_get_y */ void trigrid_fit(struct trigrid_data * data) { unsigned int X = data->X, Y = data->Y; const size_t n = X * Y * 2; unsigned int x, y, i; int status; size_t iter = 0; #ifdef USE_DERIVATIVES gsl_multiroot_function_fdf f = {&trigrid_f, &trigrid_df, &trigrid_fdf, n, data}; #else gsl_multiroot_function f = {&trigrid_f, n, data}; #endif gsl_vector * xs = gsl_vector_alloc(n); data->xs = xs; i = 0; data->xs_start = i; for (y = 0; y != Y + 1; y++) for (x = 1; x != X; x++) gsl_vector_set(xs, i++, x + 0.1 * ((double) rand() / RAND_MAX - 0.5)); gsl_vector_set(xs, i++, X + 0.1 * ((double) rand() / RAND_MAX - 0.5)); data->ys_start = i; for (x = 0; x != X + 1; x++) for (y = 1; y != Y; y++) gsl_vector_set(xs, i++, y + 0.1 * ((double) rand() / RAND_MAX - 0.5)); gsl_vector_set(xs, i++, Y + 0.1 * ((double) rand() / RAND_MAX - 0.5)); assert(i == n); #ifdef USE_DERIVATIVES data->s = gsl_multiroot_fdfsolver_alloc(SOLVER, n); gsl_multiroot_fdfsolver_set(data->s, &f, xs); #else data->s = gsl_multiroot_fsolver_alloc(SOLVER, n); gsl_multiroot_fsolver_set(data->s, &f, xs); #endif /* trigrid_print(data); */ do { iter++; fprintf(stderr, "iter = %3u\n", iter); #ifdef USE_DERIVATIVES status = gsl_multiroot_fdfsolver_iterate(data->s); #else status = gsl_multiroot_fsolver_iterate(data->s); #endif /* trigrid_print(data); */ if (status) break; status = gsl_multiroot_test_residual(data->s->f, 0.01); } while (status == GSL_CONTINUE && iter != 1000); fprintf(stderr, "status = %s\n", gsl_strerror(status)); data->status = status; data->iter = iter; } /** * trigrid_f -- function evaluator for triangular grid fitter */ int trigrid_f(const gsl_vector * xs, void * params, gsl_vector * f) { unsigned int x, y, X, Y, i; struct trigrid_data * data = (struct trigrid_data *) params; X = data->X; Y = data->Y; for (i = 0, y = 0; y != Y; y++) { for (x = 0; x != X; x++) { double A, v; double ax, ay, bx, by, cx, cy, dx, dy; ax = trigrid_get_x(data, xs, x, y); ay = trigrid_get_y(data, xs, x, y); bx = trigrid_get_x(data, xs, x + 1, y + 1); by = trigrid_get_y(data, xs, x + 1, y + 1); cx = trigrid_get_x(data, xs, x, y + 1); cy = trigrid_get_y(data, xs, x, y + 1); dx = trigrid_get_x(data, xs, x + 1, y); dy = trigrid_get_y(data, xs, x + 1, y); /* printf("x = %u, y = %u, a = %g %g, b = %g %g, c = %g %g, d = %g %g\n", */ /* x, y, ax, ay, bx, by, cx, cy, dx, dy); */ /* upper triangle */ A = data->A[i]; v = 0.5 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)); /* printf("upper A = %g, v = %g\n", A, v); */ gsl_vector_set(f, i++, v - A); /* lower triangle */ A = data->A[i]; v = 0.5 * (ax * (dy - by) + dx * (by - ay) + bx * (ay - dy)); /* printf("lower A = %g, v = %g\n\n", A, v); */ gsl_vector_set(f, i++, v - A); } } return GSL_SUCCESS; } /** * trigrid_df -- function derivative evaluator for triangular grid fitter */ int trigrid_df(const gsl_vector * xs, void * params, gsl_matrix * J) { unsigned int x, y, X, Y, i; struct trigrid_data * data = (struct trigrid_data *) params; X = data->X; Y = data->Y; gsl_matrix_set_zero(J); /* printf("xs =\n"); */ /* gsl_vector_fprintf(stdout, xs, "%g"); */ for (i = 0, y = 0; y != Y; y++) { for (x = 0; x != X; x++) { double ax, ay, bx, by, cx, cy, dx, dy; unsigned int axo, ayo, bxo, byo, cxo, cyo, dxo, dyo; ax = trigrid_get_x(data, xs, x, y); ay = trigrid_get_y(data, xs, x, y); bx = trigrid_get_x(data, xs, x + 1, y + 1); by = trigrid_get_y(data, xs, x + 1, y + 1); cx = trigrid_get_x(data, xs, x, y + 1); cy = trigrid_get_y(data, xs, x, y + 1); dx = trigrid_get_x(data, xs, x + 1, y); dy = trigrid_get_y(data, xs, x + 1, y); axo = trigrid_offset_x(data, x, y); ayo = trigrid_offset_y(data, x, y); bxo = trigrid_offset_x(data, x + 1, y + 1); byo = trigrid_offset_y(data, x + 1, y + 1); cxo = trigrid_offset_x(data, x, y + 1); cyo = trigrid_offset_y(data, x, y + 1); dxo = trigrid_offset_x(data, x + 1, y); dyo = trigrid_offset_y(data, x + 1, y); /* printf("x = %u, y = %u, a = %g %g, b = %g %g, c = %g %g, d = %g %g\n", */ /* x, y, ax, ay, bx, by, cx, cy, dx, dy); */ /* upper triangle */ /* v = 0.5 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)); */ if (axo != CONSTANT) gsl_matrix_set(J, i, axo, 0.5 * (by - cy)); if (ayo != CONSTANT) gsl_matrix_set(J, i, ayo, 0.5 * (cx - bx)); if (bxo != CONSTANT) gsl_matrix_set(J, i, bxo, 0.5 * (cy - ay)); if (byo != CONSTANT) gsl_matrix_set(J, i, byo, 0.5 * (ax - cx)); if (cxo != CONSTANT) gsl_matrix_set(J, i, cxo, 0.5 * (ay - by)); if (cyo != CONSTANT) gsl_matrix_set(J, i, cyo, 0.5 * (bx - ax)); i++; /* lower triangle */ /* v = 0.5 * (ax * (dy - by) + dx * (by - ay) + bx * (ay - dy)); */ if (axo != CONSTANT) gsl_matrix_set(J, i, axo, 0.5 * (dy - by)); if (ayo != CONSTANT) gsl_matrix_set(J, i, ayo, 0.5 * (bx - dx)); if (dxo != CONSTANT) gsl_matrix_set(J, i, dxo, 0.5 * (by - ay)); if (dyo != CONSTANT) gsl_matrix_set(J, i, dyo, 0.5 * (ax - bx)); if (bxo != CONSTANT) gsl_matrix_set(J, i, bxo, 0.5 * (ay - dy)); if (byo != CONSTANT) gsl_matrix_set(J, i, byo, 0.5 * (dx - ax)); i++; } } /* printf("J =\n"); gsl_matrix_fprintf(stdout, J, "%f"); printf("\n"); */ { gsl_matrix * JJ = gsl_matrix_alloc(2 * data->X * data->Y, 2 * data->X * data->Y); gsl_permutation * p = gsl_permutation_alloc(2 * data->X * data->Y); int signum; gsl_matrix_memcpy(JJ, J); gsl_linalg_LU_decomp(JJ, p, &signum); fprintf(stderr, "det = %g\n", gsl_linalg_LU_det(JJ, signum)); } return GSL_SUCCESS; } int trigrid_fdf(const gsl_vector * xs, void * params, gsl_vector * f, gsl_matrix * J) { trigrid_f(xs, params, f); trigrid_df(xs, params, J); return GSL_SUCCESS; } /** * trigrid_get_[xy] -- extract grid coordinates from a struct trigrid_data */ double trigrid_get_x(const struct trigrid_data * data, const gsl_vector * xs, unsigned int x, unsigned int y) { unsigned int i = trigrid_offset_x(data, x, y); if (i != CONSTANT) return gsl_vector_get(xs, i); if (x == 0) return 0; if (x == data->X) return data->X; assert(0); } unsigned int trigrid_offset_x(const struct trigrid_data * data, unsigned int x, unsigned int y) { if ((x == data->X) && (y == data->Y)) /* top right corner */ return data->ys_start - 1; if (x == 0) return CONSTANT; if (x == data->X) return CONSTANT; return data->xs_start + y * (data->X - 1) + x - 1; } double trigrid_get_y(const struct trigrid_data * data, const gsl_vector * xs, unsigned int x, unsigned int y) { unsigned int i = trigrid_offset_y(data, x, y); if (i != CONSTANT) return gsl_vector_get(xs, i); if (y == 0) return 0; if (y == data->Y) return data->Y; assert(0); } unsigned int trigrid_offset_y(const struct trigrid_data * data, unsigned int x, unsigned int y) { if ((x == data->X) && (y == data->Y)) /* top right corner */ return data->ys_start + (data->X + 1) * (data->Y - 1); if (y == 0) return CONSTANT; if (y == data->Y) return CONSTANT; return data->ys_start + x * (data->Y - 1) + y - 1; } int main(void) { unsigned int X = 10, Y = 10; double A[] = { 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.7,0.7, 0.7,0.7, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.7,0.7, 0.7,0.7, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.7,0.7, 0.7,0.7, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.7,0.7, 0.7,0.7, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.1,0.1, 0.1,0.1, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.1,0.1, 0.1,0.1, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5, 0.5,0.5 }; struct trigrid_data data = {X, Y, A, 0, 0, 0, 0, 0, 0}; trigrid_fit(&data); trigrid_print(&data); return 0; } void trigrid_print(struct trigrid_data * data) { unsigned int x, y, i = 0; #ifdef USE_DERIVATIVES gsl_vector * root = gsl_multiroot_fdfsolver_root(data->s); #else gsl_vector * root = gsl_multiroot_fsolver_root(data->s); #endif fprintf(stderr, "root =\n"); gsl_vector_fprintf(stderr, root, "%g"); fprintf(stderr, "\n"); fprintf(stderr, "f =\n"); gsl_vector_fprintf(stderr, data->s->f, "%g"); fprintf(stderr, "\n"); printf("PROCClosedLines\n\n"); printf("PROCFont(\"Corpus.Medium\", 5, 80)\n"); for (y = 0; y != data->Y; y++) { for (x = 0; x != data->X; x++) { double ax, ay, bx, by, cx, cy, dx, dy; ax = trigrid_get_x(data, root, x, y); ay = trigrid_get_y(data, root, x, y); bx = trigrid_get_x(data, root, x + 1, y + 1); by = trigrid_get_y(data, root, x + 1, y + 1); cx = trigrid_get_x(data, root, x, y + 1); cy = trigrid_get_y(data, root, x, y + 1); dx = trigrid_get_x(data, root, x + 1, y); dy = trigrid_get_y(data, root, x + 1, y); /* printf("%.3f %.3f ", ax, ay);*/ printf("PROCGroup\n"); printf("PROCMove(%g, %g)\n", ax, ay); printf("PROCDraw(%g, %g)\n", bx, by); printf("PROCDraw(%g, %g)\n", cx, cy); printf("PROCPrint(\"%.3f\", %g, %g)\n", /*data->A[i] +*/ gsl_vector_get(data->s->f, i), (ax + bx + cx) / 3, (ay + by + cy) / 3); printf("PROCEndGroup\n\n"); i++; printf("PROCGroup\n"); printf("PROCMove(%g, %g)\n", ax, ay); printf("PROCDraw(%g, %g)\n", dx, dy); printf("PROCDraw(%g, %g)\n", bx, by); printf("PROCPrint(\"%.3f\", %g, %g)\n", /*data->A[i] +*/ gsl_vector_get(data->s->f, i), (ax + dx + bx) / 3, (ay + dy + by) / 3); printf("PROCEndGroup\n\n"); i++; } printf("\n"); } printf("\n"); printf("PROCPrint(\"'%s' solver, %u iterations, end status '%s'\", 0, %u)\n", #ifdef USE_DERIVATIVES gsl_multiroot_fdfsolver_name(data->s), #else gsl_multiroot_fsolver_name(data->s), #endif data->iter, gsl_strerror(data->status), data->Y + 1); }