From a2a9a4659ddf54e22bbf3545d7830f3f2d50b487 Mon Sep 17 00:00:00 2001 From: Aymeric Stamm Date: Thu, 17 Apr 2025 22:41:58 +0200 Subject: [PATCH 1/3] Add cmake variable to enable compilation without R-incompatible functions. --- CMakeLists.txt | 19 +-- src/algs/cobyla/cobyla.c | 184 +++++++++++++++++------------- src/algs/direct/direct-internal.h | 66 ++++++----- src/api/nlopt-internal.h | 2 + src/api/optimize.c | 6 + src/util/nlopt-util.h | 2 + src/util/stop.c | 4 + 7 files changed, 165 insertions(+), 118 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7f65733d..22d64187d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,11 +46,16 @@ option (NLOPT_JAVA "build java bindings" ON) option (NLOPT_SWIG "use SWIG to build bindings" ON) option (NLOPT_LUKSAN "enable LGPL Luksan solvers" ON) option (NLOPT_TESTS "build unit tests" OFF) +option (USE_R_COMPATIBILITY "compile with R compatibility functions only" OFF) if (NLOPT_FORTRAN) enable_language (Fortran) endif () +if (USE_R_COMPATIBILITY) + add_definitions(-DCRAN_COMPATIBILITY) +endif () + include (GNUInstallDirs) # Offer the user the choice of overriding the installation directories @@ -240,7 +245,7 @@ if (NLOPT_LUKSAN) target_compile_definitions (${nlopt_lib} PRIVATE NLOPT_LUKSAN) endif () if (M_LIBRARY) - target_link_libraries (${nlopt_lib} ${M_LIBRARY}) +target_link_libraries (${nlopt_lib} ${M_LIBRARY}) endif () set_target_properties (${nlopt_lib} PROPERTIES SOVERSION ${SO_MAJOR}) set_target_properties (${nlopt_lib} PROPERTIES VERSION "${SO_MAJOR}.${SO_MINOR}.${SO_PATCH}") @@ -310,12 +315,12 @@ if (UNIX) endif () if (NLOPT_PYTHON) - option (NLOPT_PYTHON_SABI "Use Python stable ABI" OFF) - if (NLOPT_PYTHON_SABI AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.26) - find_package (Python 3.6 COMPONENTS Interpreter Development.SABIModule NumPy) - add_library (Python::Module ALIAS Python::SABIModule) - else () - find_package (Python 3.6 COMPONENTS Interpreter Development.Module NumPy) + option (NLOPT_PYTHON_SABI "Use Python stable ABI" OFF) + if (NLOPT_PYTHON_SABI AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.26) + find_package (Python 3.6 COMPONENTS Interpreter Development.SABIModule NumPy) + add_library (Python::Module ALIAS Python::SABIModule) + else () + find_package (Python 3.6 COMPONENTS Interpreter Development.Module NumPy) endif () endif () diff --git a/src/algs/cobyla/cobyla.c b/src/algs/cobyla/cobyla.c index 6dc7e6253..ec3dbd94c 100644 --- a/src/algs/cobyla/cobyla.c +++ b/src/algs/cobyla/cobyla.c @@ -3,7 +3,7 @@ /* * Copyright (c) 1992, Michael J. D. Powell (M.J.D.Powell@damtp.cam.ac.uk) * Copyright (c) 2004, Jean-Sebastien Roy (js@jeannot.org) - * + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including @@ -11,10 +11,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,7 +27,7 @@ /* * This software is a C version of COBYLA2, a contrained optimization by linear * approximation package developed by Michael J. D. Powell in Fortran. - * + * * The original source code can be found at : * http://plato.la.asu.edu/topics/problems/nlores.html * @@ -193,7 +193,7 @@ nlopt_result cobyla_minimize(unsigned n, nlopt_func f, void *f_data, s.f = f; s.f_data = f_data; s.m_orig = m; - s.fc = fc; + s.fc = fc; s.p = p; s.h = h; s.stop = stop; @@ -252,7 +252,7 @@ nlopt_result cobyla_minimize(unsigned n, nlopt_func f, void *f_data, nlopt_rescale(n, s.scale, x, x); ret = cobyla((int) n, (int) m, x, minf, rhobeg, rhoend, - stop, s.lb, s.ub, COBYLA_MSG_NONE, + stop, s.lb, s.ub, COBYLA_MSG_NONE, func_wrap, &s); nlopt_unscale(n, s.scale, x, x); @@ -332,58 +332,58 @@ nlopt_result cobyla(int n, int m, double *x, double *minf, double rhobeg, double /* * This subroutine minimizes an objective function F(X) subject to M - * inequality constraints on X, where X is a vector of variables that has - * N components. The algorithm employs linear approximations to the - * objective and constraint functions, the approximations being formed by - * linear interpolation at N+1 points in the space of the variables. - * We regard these interpolation points as vertices of a simplex. The - * parameter RHO controls the size of the simplex and it is reduced - * automatically from RHOBEG to RHOEND. For each RHO the subroutine tries - * to achieve a good vector of variables for the current size, and then - * RHO is reduced until the value RHOEND is reached. Therefore RHOBEG and - * RHOEND should be set to reasonable initial changes to and the required - * accuracy in the variables respectively, but this accuracy should be - * viewed as a subject for experimentation because it is not guaranteed. - * The subroutine has an advantage over many of its competitors, however, - * which is that it treats each constraint individually when calculating - * a change to the variables, instead of lumping the constraints together - * into a single penalty function. The name of the subroutine is derived - * from the phrase Constrained Optimization BY Linear Approximations. + * inequality constraints on X, where X is a vector of variables that has + * N components. The algorithm employs linear approximations to the + * objective and constraint functions, the approximations being formed by + * linear interpolation at N+1 points in the space of the variables. + * We regard these interpolation points as vertices of a simplex. The + * parameter RHO controls the size of the simplex and it is reduced + * automatically from RHOBEG to RHOEND. For each RHO the subroutine tries + * to achieve a good vector of variables for the current size, and then + * RHO is reduced until the value RHOEND is reached. Therefore RHOBEG and + * RHOEND should be set to reasonable initial changes to and the required + * accuracy in the variables respectively, but this accuracy should be + * viewed as a subject for experimentation because it is not guaranteed. + * The subroutine has an advantage over many of its competitors, however, + * which is that it treats each constraint individually when calculating + * a change to the variables, instead of lumping the constraints together + * into a single penalty function. The name of the subroutine is derived + * from the phrase Constrained Optimization BY Linear Approximations. * - * The user must set the values of N, M, RHOBEG and RHOEND, and must - * provide an initial vector of variables in X. Further, the value of - * IPRINT should be set to 0, 1, 2 or 3, which controls the amount of - * printing during the calculation. Specifically, there is no output if - * IPRINT=0 and there is output only at the end of the calculation if - * IPRINT=1. Otherwise each new value of RHO and SIGMA is printed. - * Further, the vector of variables and some function information are - * given either when RHO is reduced or when each new value of F(X) is - * computed in the cases IPRINT=2 or IPRINT=3 respectively. Here SIGMA - * is a penalty parameter, it being assumed that a change to X is an - * improvement if it reduces the merit function - * F(X)+SIGMA*MAX(0.0,-C1(X),-C2(X),...,-CM(X)), - * where C1,C2,...,CM denote the constraint functions that should become - * nonnegative eventually, at least to the precision of RHOEND. In the - * printed output the displayed term that is multiplied by SIGMA is - * called MAXCV, which stands for 'MAXimum Constraint Violation'. The - * argument MAXFUN is an int variable that must be set by the user to a - * limit on the number of calls of CALCFC, the purpose of this routine being - * given below. The value of MAXFUN will be altered to the number of calls - * of CALCFC that are made. The arguments W and IACT provide real and - * int arrays that are used as working space. Their lengths must be at - * least N*(3*N+2*M+11)+4*M+6 and M+1 respectively. + * The user must set the values of N, M, RHOBEG and RHOEND, and must + * provide an initial vector of variables in X. Further, the value of + * IPRINT should be set to 0, 1, 2 or 3, which controls the amount of + * printing during the calculation. Specifically, there is no output if + * IPRINT=0 and there is output only at the end of the calculation if + * IPRINT=1. Otherwise each new value of RHO and SIGMA is printed. + * Further, the vector of variables and some function information are + * given either when RHO is reduced or when each new value of F(X) is + * computed in the cases IPRINT=2 or IPRINT=3 respectively. Here SIGMA + * is a penalty parameter, it being assumed that a change to X is an + * improvement if it reduces the merit function + * F(X)+SIGMA*MAX(0.0,-C1(X),-C2(X),...,-CM(X)), + * where C1,C2,...,CM denote the constraint functions that should become + * nonnegative eventually, at least to the precision of RHOEND. In the + * printed output the displayed term that is multiplied by SIGMA is + * called MAXCV, which stands for 'MAXimum Constraint Violation'. The + * argument MAXFUN is an int variable that must be set by the user to a + * limit on the number of calls of CALCFC, the purpose of this routine being + * given below. The value of MAXFUN will be altered to the number of calls + * of CALCFC that are made. The arguments W and IACT provide real and + * int arrays that are used as working space. Their lengths must be at + * least N*(3*N+2*M+11)+4*M+6 and M+1 respectively. * - * In order to define the objective and constraint functions, we require - * a subroutine that has the name and arguments - * SUBROUTINE CALCFC (N,M,X,F,CON) - * DIMENSION X(*),CON(*) . - * The values of N and M are fixed and have been defined already, while - * X is now the current vector of variables. The subroutine should return - * the objective and constraint functions at X in F and CON(1),CON(2), - * ...,CON(M). Note that we are trying to adjust X so that F(X) is as - * small as possible subject to the constraint functions being nonnegative. + * In order to define the objective and constraint functions, we require + * a subroutine that has the name and arguments + * SUBROUTINE CALCFC (N,M,X,F,CON) + * DIMENSION X(*),CON(*) . + * The values of N and M are fixed and have been defined already, while + * X is now the current vector of variables. The subroutine should return + * the objective and constraint functions at X in F and CON(1),CON(2), + * ...,CON(M). Note that we are trying to adjust X so that F(X) is as + * small as possible subject to the constraint functions being nonnegative. * - * Partition the working space array W to provide the storage that is needed + * Partition the working space array W to provide the storage that is needed * for the main calculation. */ @@ -391,13 +391,17 @@ nlopt_result cobyla(int n, int m, double *x, double *minf, double rhobeg, double if (n == 0) { +#ifndef CRAN_COMPATIBILITY if (iprint>=1) fprintf(stderr, "cobyla: N==0.\n"); +#endif return NLOPT_SUCCESS; } if (n < 0 || m < 0) { +#ifndef CRAN_COMPATIBILITY if (iprint>=1) fprintf(stderr, "cobyla: N<0 or M<0.\n"); +#endif return NLOPT_INVALID_ARGS; } @@ -405,17 +409,21 @@ nlopt_result cobyla(int n, int m, double *x, double *minf, double rhobeg, double w = (double*) malloc(U(n*(3*n+2*m+11)+4*m+6)*sizeof(*w)); if (w == NULL) { +#ifndef CRAN_COMPATIBILITY if (iprint>=1) fprintf(stderr, "cobyla: memory allocation error.\n"); +#endif return NLOPT_OUT_OF_MEMORY; } iact = (int*)malloc(U(m+1)*sizeof(*iact)); if (iact == NULL) { +#ifndef CRAN_COMPATIBILITY if (iprint>=1) fprintf(stderr, "cobyla: memory allocation error.\n"); +#endif free(w); return NLOPT_OUT_OF_MEMORY; } - + /* Parameter adjustments */ --iact; --w; @@ -444,7 +452,7 @@ nlopt_result cobyla(int n, int m, double *x, double *minf, double rhobeg, double free(w); free(iact); - + return rc; } /* cobyla */ @@ -452,13 +460,13 @@ nlopt_result cobyla(int n, int m, double *x, double *minf, double rhobeg, double static nlopt_result cobylb(int *n, int *m, int *mpp, double *x, double *minf, double *rhobeg, double rhoend, nlopt_stopping *stop, const double *lb, const double *ub, - int *iprint, double *con, double *sim, double *simi, + int *iprint, double *con, double *sim, double *simi, double *datmat, double *a, double *vsig, double *veta, double *sigbar, double *dx, double *w, int *iact, cobyla_function *calcfc, func_wrap_state *state) { /* System generated locals */ - int sim_dim1, sim_offset, simi_dim1, simi_offset, datmat_dim1, + int sim_dim1, sim_offset, simi_dim1, simi_offset, datmat_dim1, datmat_offset, a_dim1, a_offset, i__1, i__2, i__3; double d__1, d__2; @@ -530,11 +538,13 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, delta = 1.1; rho = *rhobeg; parmu = 0.; +#ifndef CRAN_COMPATIBILITY if (*iprint >= 2) { fprintf(stderr, "cobyla: the initial value of RHO is %12.6E and PARMU is set to zero.\n", rho); } +#endif temp = 1. / rho; i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { @@ -581,9 +591,11 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, ++ *(stop->nevals_p); if (calcfc(*n, *m, &x[1], &f, &con[1], state)) { +#ifndef CRAN_COMPATIBILITY if (*iprint >= 1) { fprintf(stderr, "cobyla: user requested end of minimization.\n"); } +#endif rc = NLOPT_FORCED_STOP; goto L600; } @@ -606,6 +618,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, goto L620; /* not L600 because we want to use current x, f, resmax */ } +#ifndef CRAN_COMPATIBILITY if (*(stop->nevals_p) == *iprint - 1 || *iprint == 3) { fprintf(stderr, "cobyla: NFVALS = %4d, F =%13.6E, MAXCV =%13.6E\n", *(stop->nevals_p), f, resmax); @@ -624,6 +637,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } fprintf(stderr, "\n"); } +#endif con[mp] = f; con[*mpp] = resmax; if (ibrnch == 1) { @@ -688,18 +702,18 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, /* Identify the optimal vertex of the current simplex. */ L140: - phimin = datmat[mp + np * datmat_dim1] + parmu * datmat[*mpp + np * + phimin = datmat[mp + np * datmat_dim1] + parmu * datmat[*mpp + np * datmat_dim1]; nbest = np; i__1 = *n; for (j = 1; j <= i__1; ++j) { - temp = datmat[mp + j * datmat_dim1] + parmu * datmat[*mpp + j * + temp = datmat[mp + j * datmat_dim1] + parmu * datmat[*mpp + j * datmat_dim1]; if (temp < phimin) { nbest = j; phimin = temp; } else if (temp == phimin && parmu == 0.) { - if (datmat[*mpp + j * datmat_dim1] < datmat[*mpp + nbest * + if (datmat[*mpp + j * datmat_dim1] < datmat[*mpp + nbest * datmat_dim1]) { nbest = j; } @@ -753,9 +767,11 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } } if (error > .1) { +#ifndef CRAN_COMPATIBILITY if (*iprint >= 1) { fprintf(stderr, "cobyla: rounding errors are becoming damaging.\n"); } +#endif rc = NLOPT_ROUNDOFF_LIMITED; goto L600; } @@ -905,7 +921,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } i__2 = *n; for (i__ = 1; i__ <= i__2; ++i__) { - simi[j + i__ * simi_dim1] -= temp * simi[jdrop + i__ * + simi[j + i__ * simi_dim1] -= temp * simi[jdrop + i__ * simi_dim1]; } } @@ -978,20 +994,22 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } if (parmu < barmu * 1.5) { parmu = barmu * 2.; +#ifndef CRAN_COMPATIBILITY if (*iprint >= 2) { fprintf(stderr, "cobyla: increase in PARMU to %12.6E\n", parmu); } - phi = datmat[mp + np * datmat_dim1] + parmu * datmat[*mpp + np * +#endif + phi = datmat[mp + np * datmat_dim1] + parmu * datmat[*mpp + np * datmat_dim1]; i__1 = *n; for (j = 1; j <= i__1; ++j) { - temp = datmat[mp + j * datmat_dim1] + parmu * datmat[*mpp + j * + temp = datmat[mp + j * datmat_dim1] + parmu * datmat[*mpp + j * datmat_dim1]; if (temp < phi) { goto L140; } if (temp == phi && parmu == 0.f) { - if (datmat[*mpp + j * datmat_dim1] < datmat[*mpp + np * + if (datmat[*mpp + j * datmat_dim1] < datmat[*mpp + np * datmat_dim1]) { goto L140; } @@ -1010,7 +1028,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, ibrnch = 1; goto L40; L440: - vmold = datmat[mp + np * datmat_dim1] + parmu * datmat[*mpp + np * + vmold = datmat[mp + np * datmat_dim1] + parmu * datmat[*mpp + np * datmat_dim1]; vmnew = f + parmu * resmax; trured = vmold - vmnew; @@ -1096,7 +1114,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } i__2 = *n; for (i__ = 1; i__ <= i__2; ++i__) { - simi[j + i__ * simi_dim1] -= temp * simi[jdrop + i__ * + simi[j + i__ * simi_dim1] -= temp * simi[jdrop + i__ * simi_dim1]; } } @@ -1113,7 +1131,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, mentions a similar modification to COBYLA, although they didn't publish their source code), increase rho if predicted reduction is sufficiently close to the actual reduction. Otherwise, - COBLYA seems to easily get stuck making very small steps. + COBLYA seems to easily get stuck making very small steps. Also require iflag != 0 (i.e., acceptable simplex), again following SAS suggestion (otherwise I get convergence failure in some cases.) */ @@ -1177,6 +1195,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, parmu = (cmax - cmin) / denom; } } +#ifndef CRAN_COMPATIBILITY if (*iprint >= 2) { fprintf(stderr, "cobyla: reduction in RHO to %12.6E and PARMU =%13.6E\n", rho, parmu); @@ -1200,6 +1219,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } fprintf(stderr, "\n"); } +#endif goto L140; } else /* rho <= rhoend */ @@ -1207,9 +1227,11 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, /* Return the best calculated values of the variables. */ +#ifndef CRAN_COMPATIBILITY if (*iprint >= 1) { fprintf(stderr, "cobyla: normal return.\n"); } +#endif if (ifull == 1) { goto L620; } @@ -1222,6 +1244,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, resmax = datmat[*mpp + np * datmat_dim1]; L620: *minf = f; +#ifndef CRAN_COMPATIBILITY if (*iprint >= 1) { fprintf(stderr, "cobyla: NFVALS = %4d, F =%13.6E, MAXCV =%13.6E\n", *(stop->nevals_p), f, resmax); @@ -1240,12 +1263,13 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } fprintf(stderr, "\n"); } +#endif return rc; } /* cobylb */ /* ------------------------------------------------------------------------- */ -static nlopt_result trstlp(int *n, int *m, double *a, - double *b, double *rho, double *dx, int *ifull, +static nlopt_result trstlp(int *n, int *m, double *a, + double *b, double *rho, double *dx, int *ifull, int *iact, double *z__, double *zdota, double *vmultc, double *sdirn, double *dxnew, double *vmultd) { @@ -1434,9 +1458,9 @@ static nlopt_result trstlp(int *n, int *m, double *a, tot = temp; i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { - temp = alpha * z__[i__ + k * z_dim1] + beta * z__[i__ + kp * + temp = alpha * z__[i__ + k * z_dim1] + beta * z__[i__ + kp * z_dim1]; - z__[i__ + kp * z_dim1] = alpha * z__[i__ + kp * z_dim1] - + z__[i__ + kp * z_dim1] = alpha * z__[i__ + kp * z_dim1] - beta * z__[i__ + k * z_dim1]; z__[i__ + k * z_dim1] = temp; } @@ -1507,7 +1531,7 @@ static nlopt_result trstlp(int *n, int *m, double *a, /* new value of ZDOTA(NACT) and branch if it is not acceptable. */ i__1 = nact; - + /* This pragma fixes a known problem compiling with VS2013 or VS2015 in Release */ /* see https://connect.microsoft.com/VisualStudio/feedback/details/1028781/c1001-on-release-build */ #if defined(_MSC_VER) && _MSC_VER >= 1800 @@ -1537,9 +1561,9 @@ static nlopt_result trstlp(int *n, int *m, double *a, zdota[k] = temp; i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { - temp = alpha * z__[i__ + kp * z_dim1] + beta * z__[i__ + k * + temp = alpha * z__[i__ + kp * z_dim1] + beta * z__[i__ + k * z_dim1]; - z__[i__ + kp * z_dim1] = alpha * z__[i__ + k * z_dim1] - beta * + z__[i__ + kp * z_dim1] = alpha * z__[i__ + k * z_dim1] - beta * z__[i__ + kp * z_dim1]; z__[i__ + k * z_dim1] = temp; } @@ -1585,9 +1609,9 @@ static nlopt_result trstlp(int *n, int *m, double *a, zdota[k] = temp; i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { - temp = alpha * z__[i__ + nact * z_dim1] + beta * z__[i__ + k * + temp = alpha * z__[i__ + nact * z_dim1] + beta * z__[i__ + k * z_dim1]; - z__[i__ + nact * z_dim1] = alpha * z__[i__ + k * z_dim1] - beta * + z__[i__ + nact * z_dim1] = alpha * z__[i__ + k * z_dim1] - beta * z__[i__ + nact * z_dim1]; z__[i__ + k * z_dim1] = temp; } @@ -1641,9 +1665,9 @@ static nlopt_result trstlp(int *n, int *m, double *a, zdota[k] = temp; i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { - temp = alpha * z__[i__ + kp * z_dim1] + beta * z__[i__ + k * + temp = alpha * z__[i__ + kp * z_dim1] + beta * z__[i__ + k * z_dim1]; - z__[i__ + kp * z_dim1] = alpha * z__[i__ + k * z_dim1] - beta * + z__[i__ + kp * z_dim1] = alpha * z__[i__ + k * z_dim1] - beta * z__[i__ + kp * z_dim1]; z__[i__ + k * z_dim1] = temp; } diff --git a/src/algs/direct/direct-internal.h b/src/algs/direct/direct-internal.h index fb4b274ac..3a1240a61 100644 --- a/src/algs/direct/direct-internal.h +++ b/src/algs/direct/direct-internal.h @@ -17,7 +17,11 @@ typedef int integer; typedef double doublereal; typedef direct_objective_func fp; +#ifndef CRAN_COMPATIBILITY #define ASRT(c) if (!(c)) { fprintf(stderr, "DIRECT assertion failure at " __FILE__ ":%d -- " #c "\n", __LINE__); exit(EXIT_FAILURE); } +#else +#define ASRT(c) if (!(c)) { } +#endif #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) @@ -44,7 +48,7 @@ extern void direct_dirinit_( extern void direct_dirinitlist_( integer *anchor, integer *free, integer * point, doublereal *f, integer *maxfunc, const integer *maxdeep); -extern void direct_dirpreprc_(doublereal *u, doublereal *l, integer *n, +extern void direct_dirpreprc_(doublereal *u, doublereal *l, integer *n, doublereal *xs1, doublereal *xs2, integer *oops); extern void direct_dirchoose_( integer *anchor, integer *s, integer *actdeep, @@ -53,66 +57,66 @@ extern void direct_dirchoose_( const integer *maxdiv, integer *n, FILE *logfile, integer *cheat, doublereal *kmax, integer *ifeasiblef, integer jones); extern void direct_dirdoubleinsert_( - integer *anchor, integer *s, integer *maxpos, integer *point, - doublereal *f, const integer *maxdeep, integer *maxfunc, + integer *anchor, integer *s, integer *maxpos, integer *point, + doublereal *f, const integer *maxdeep, integer *maxfunc, const integer *maxdiv, integer *ierror); extern integer direct_dirgetmaxdeep_(integer *pos, integer *length, integer *maxfunc, integer *n); extern void direct_dirget_i__( - integer *length, integer *pos, integer *arrayi, integer *maxi, + integer *length, integer *pos, integer *arrayi, integer *maxi, integer *n, integer *maxfunc); extern void direct_dirsamplepoints_( - doublereal *c__, integer *arrayi, - doublereal *delta, integer *sample, integer *start, integer *length, - FILE *logfile, doublereal *f, integer *free, + doublereal *c__, integer *arrayi, + doublereal *delta, integer *sample, integer *start, integer *length, + FILE *logfile, doublereal *f, integer *free, integer *maxi, integer *point, doublereal *x, doublereal *l, - doublereal *minf, integer *minpos, doublereal *u, integer *n, + doublereal *minf, integer *minpos, doublereal *u, integer *n, integer *maxfunc, const integer *maxdeep, integer *oops); extern void direct_dirdivide_( - integer *new__, integer *currentlength, - integer *length, integer *point, integer *arrayi, integer *sample, - integer *list2, doublereal *w, integer *maxi, doublereal *f, + integer *new__, integer *currentlength, + integer *length, integer *point, integer *arrayi, integer *sample, + integer *list2, doublereal *w, integer *maxi, doublereal *f, integer *maxfunc, const integer *maxdeep, integer *n); extern void direct_dirinsertlist_( - integer *new__, integer *anchor, integer *point, doublereal *f, - integer *maxi, integer *length, integer *maxfunc, + integer *new__, integer *anchor, integer *point, doublereal *f, + integer *maxi, integer *length, integer *maxfunc, const integer *maxdeep, integer *n, integer *samp, integer jones); extern void direct_dirreplaceinf_( - integer *free, integer *freeold, - doublereal *f, doublereal *c__, doublereal *thirds, integer *length, - integer *anchor, integer *point, doublereal *c1, doublereal *c2, - integer *maxfunc, const integer *maxdeep, integer *maxdim, integer *n, + integer *free, integer *freeold, + doublereal *f, doublereal *c__, doublereal *thirds, integer *length, + integer *anchor, integer *point, doublereal *c1, doublereal *c2, + integer *maxfunc, const integer *maxdeep, integer *maxdim, integer *n, FILE *logfile, doublereal *fmax, integer jones); extern void direct_dirsummary_( - FILE *logfile, doublereal *x, doublereal *l, doublereal *u, - integer *n, doublereal *minf, doublereal *fglobal, + FILE *logfile, doublereal *x, doublereal *l, doublereal *u, + integer *n, doublereal *minf, doublereal *fglobal, integer *numfunc, integer *ierror); extern integer direct_dirgetlevel_( - integer *pos, integer *length, + integer *pos, integer *length, integer *maxfunc, integer *n, integer jones); extern void direct_dirinfcn_( - fp fcn, doublereal *x, doublereal *c1, - doublereal *c2, integer *n, doublereal *f, integer *flag__, + fp fcn, doublereal *x, doublereal *c1, + doublereal *c2, integer *n, doublereal *f, integer *flag__, void *fcn_data); /* DIRserial.c / DIRparallel.c */ extern void direct_dirsamplef_( - doublereal *c__, integer *arrayi, doublereal - *delta, integer *sample, integer *new__, integer *length, - FILE *logfile, doublereal *f, integer *free, integer *maxi, + doublereal *c__, integer *arrayi, doublereal + *delta, integer *sample, integer *new__, integer *length, + FILE *logfile, doublereal *f, integer *free, integer *maxi, integer *point, fp fcn, doublereal *x, doublereal *l, doublereal * - minf, integer *minpos, doublereal *u, integer *n, integer *maxfunc, + minf, integer *minpos, doublereal *u, integer *n, integer *maxfunc, const integer *maxdeep, integer *oops, doublereal *fmax, integer * ifeasiblef, integer *iinfesiblef, void *fcn_data, int *force_stop); /* DIRect.c */ extern void direct_direct_( fp fcn, doublereal *x, integer *n, doublereal *eps, doublereal epsabs, - integer *maxf, integer *maxt, - double starttime, double maxtime, - int *force_stop, doublereal *minf, doublereal *l, - doublereal *u, integer *algmethod, integer *ierror, FILE *logfile, - doublereal *fglobal, doublereal *fglper, doublereal *volper, + integer *maxf, integer *maxt, + double starttime, double maxtime, + int *force_stop, doublereal *minf, doublereal *l, + doublereal *u, integer *algmethod, integer *ierror, FILE *logfile, + doublereal *fglobal, doublereal *fglper, doublereal *volper, doublereal *sigmaper, void *fcn_data); #ifdef __cplusplus diff --git a/src/api/nlopt-internal.h b/src/api/nlopt-internal.h index e191f153a..9d660c628 100644 --- a/src/api/nlopt-internal.h +++ b/src/api/nlopt-internal.h @@ -107,7 +107,9 @@ extern "C" { extern const char *nlopt_set_errmsg(nlopt_opt opt, const char *format, ...) #ifdef __GNUC__ +#ifndef CRAN_COMPATIBILITY __attribute__ ((format(printf, 2, 3))) +#endif #endif ; extern void nlopt_unset_errmsg(nlopt_opt opt); diff --git a/src/api/optimize.c b/src/api/optimize.c index 4cc6583b3..45170e047 100644 --- a/src/api/optimize.c +++ b/src/api/optimize.c @@ -717,7 +717,9 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) #ifdef NLOPT_LUKSAN return luksan_plis(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage, nlopt_get_param(opt, "tolg", 0.)); #else +#ifndef CRAN_COMPATIBILITY printf("ERROR - attempting to use NLOPT_LD_LBFGS, but Luksan code disabled\n"); +#endif return NLOPT_INVALID_ARGS; #endif @@ -726,7 +728,9 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) #ifdef NLOPT_LUKSAN return luksan_plip(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage, algorithm == NLOPT_LD_VAR1 ? 1 : 2, nlopt_get_param(opt, "tolg", 0.)); #else +#ifndef CRAN_COMPATIBILITY printf("ERROR - attempting to use NLOPT_LD_VAR*, but Luksan code disabled\n"); +#endif return NLOPT_INVALID_ARGS; #endif @@ -737,7 +741,9 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) #ifdef NLOPT_LUKSAN return luksan_pnet(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage, 1 + (algorithm - NLOPT_LD_TNEWTON) % 2, 1 + (algorithm - NLOPT_LD_TNEWTON) / 2, nlopt_get_param(opt, "tolg", 0.)); #else +#ifndef CRAN_COMPATIBILITY printf("ERROR - attempting to use NLOPT_LD_TNEWTON*, but Luksan code disabled\n"); +#endif return NLOPT_INVALID_ARGS; #endif diff --git a/src/util/nlopt-util.h b/src/util/nlopt-util.h index 40963b7f2..ef1f6db72 100644 --- a/src/util/nlopt-util.h +++ b/src/util/nlopt-util.h @@ -104,7 +104,9 @@ extern "C" { extern char *nlopt_vsprintf(char *p, const char *format, va_list ap); extern void nlopt_stop_msg(const nlopt_stopping * s, const char *format, ...) #ifdef __GNUC__ +#ifndef CRAN_COMPATIBILITY __attribute__ ((format(printf, 2, 3))) +#endif #endif ; diff --git a/src/util/stop.c b/src/util/stop.c index bf21c38ed..dc4c90f15 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -189,8 +189,10 @@ char *nlopt_vsprintf(char *p, const char *format, va_list ap) int ret; p = (char *) realloc(p, len); +#ifndef CRAN_COMPATIBILITY if (!p) abort(); +#endif /* TODO: check HAVE_VSNPRINTF, and fallback to vsprintf otherwise */ while ((ret = vsnprintf(p, len, format, ap)) < 0 || (size_t) ret >= len) { @@ -198,8 +200,10 @@ char *nlopt_vsprintf(char *p, const char *format, va_list ap) if the buffer is too small; older versions (e.g. MS) return -1 */ len = ret >= 0 ? (size_t) (ret + 1) : (len * 3) >> 1; p = (char *) realloc(p, len); +#ifndef CRAN_COMPATIBILITY if (!p) abort(); +#endif } return p; } From 98b762a827d6dfcae779ab9b5fc8b7b48ead9573 Mon Sep 17 00:00:00 2001 From: Aymeric Stamm Date: Sat, 19 Apr 2025 23:07:04 +0200 Subject: [PATCH 2/3] Fix remaining calls to printf. --- src/algs/auglag/auglag.c | 44 +++++++++++++++++++++-------------- src/algs/mma/ccsa_quadratic.c | 39 ++++++++++++++++++++----------- src/algs/mma/mma.c | 43 ++++++++++++++++++++++------------ src/algs/neldermead/sbplx.c | 26 +++++++++++++-------- 4 files changed, 96 insertions(+), 56 deletions(-) diff --git a/src/algs/auglag/auglag.c b/src/algs/auglag/auglag.c index 18e5e664f..9682429e0 100644 --- a/src/algs/auglag/auglag.c +++ b/src/algs/auglag/auglag.c @@ -43,7 +43,7 @@ static double auglag(unsigned n, const double *x, double *grad, void *data) for (k = 0; k < d->h[i].m; ++k) { double h = restmp[k] + lambda[ii++] / rho; L += 0.5 * rho * h*h; - if (grad) for (j = 0; j < n; ++j) + if (grad) for (j = 0; j < n; ++j) grad[j] += (rho * h) * gradtmp[k*n + j]; } } @@ -55,7 +55,7 @@ static double auglag(unsigned n, const double *x, double *grad, void *data) double fc = restmp[k] + mu[ii++] / rho; if (fc > 0) { L += 0.5 * rho * fc*fc; - if (grad) for (j = 0; j < n; ++j) + if (grad) for (j = 0; j < n; ++j) grad[j] += (rho * fc) * gradtmp[k*n + j]; } } @@ -109,7 +109,7 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, ret = nlopt_set_min_objective(sub_opt, auglag, &d); if (ret<0) return ret; ret = nlopt_set_lower_bounds(sub_opt, lb); if (ret<0) return ret; ret = nlopt_set_upper_bounds(sub_opt, ub); if (ret<0) return ret; - ret = nlopt_set_stopval(sub_opt, + ret = nlopt_set_stopval(sub_opt, d.m==0 && d.p==0 ? stop->minf_max : -HUGE_VAL); if (ret<0) return ret; ret = nlopt_remove_inequality_constraints(sub_opt); if (ret<0) return ret; @@ -120,7 +120,7 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, fc[i].f, fc[i].f_data, fc[i].tol[0]); else - ret = nlopt_add_inequality_mconstraint(sub_opt, fc[i].m, + ret = nlopt_add_inequality_mconstraint(sub_opt, fc[i].m, fc[i].mf, fc[i].f_data, fc[i].tol); if (ret < 0) return ret; @@ -179,32 +179,38 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, else d.rho = 1; /* whatever, doesn't matter */ +#ifndef CRAN_COMPATIBILITY if (auglag_verbose) { - printf("auglag: initial rho=%g\nauglag initial lambda=", d.rho); - for (i = 0; i < d.pp; ++i) printf(" %g", d.lambda[i]); - printf("\nauglag initial mu = "); - for (i = 0; i < d.mm; ++i) printf(" %g", d.mu[i]); - printf("\n"); + printf("auglag: initial rho=%g\nauglag initial lambda=", d.rho); + for (i = 0; i < d.pp; ++i) printf(" %g", d.lambda[i]); + printf("\nauglag initial mu = "); + for (i = 0; i < d.mm; ++i) printf(" %g", d.mu[i]); + printf("\n"); } +#endif do { double prev_ICM = ICM; - + ret = nlopt_optimize_limited(sub_opt, xcur, &fcur, stop->maxeval - *(stop->nevals_p), - stop->maxtime - (nlopt_seconds() + stop->maxtime - (nlopt_seconds() - stop->start)); +#ifndef CRAN_COMPATIBILITY if (auglag_verbose) - printf("auglag: subopt return code %d\n", ret); + printf("auglag: subopt return code %d\n", ret); +#endif if (ret < 0) break; - + ++ *(d.stop->nevals_p); fcur = f(n, xcur, NULL, f_data); if (nlopt_stop_forced(stop)) { ret = NLOPT_FORCED_STOP; goto done; } +#ifndef CRAN_COMPATIBILITY if (auglag_verbose) printf("auglag: fcur = %g\n", fcur); - +#endif + ICM = 0; penalty = 0; feasible = 1; @@ -239,7 +245,8 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, } auglag_iters++; - + +#ifndef CRAN_COMPATIBILITY if (auglag_verbose) { printf("auglag %d: ICM=%g (%sfeasible), rho=%g\nauglag lambda=", auglag_iters, ICM, feasible ? "" : "not ", d.rho); @@ -248,15 +255,16 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, for (i = 0; i < d.mm; ++i) printf(" %g", d.mu[i]); printf("\n"); } +#endif if ((feasible && (!minf_feasible || penalty < minf_penalty - || fcur < *minf)) || + || fcur < *minf)) || (!minf_feasible && penalty < minf_penalty)) { ret = NLOPT_SUCCESS; if (feasible) { - if (fcur < stop->minf_max) + if (fcur < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED; - else if (nlopt_stop_ftol(stop, fcur, *minf)) + else if (nlopt_stop_ftol(stop, fcur, *minf)) ret = NLOPT_FTOL_REACHED; else if (nlopt_stop_x(stop, xcur, x)) ret = NLOPT_XTOL_REACHED; diff --git a/src/algs/mma/ccsa_quadratic.c b/src/algs/mma/ccsa_quadratic.c index f89fc78e9..771bd620f 100644 --- a/src/algs/mma/ccsa_quadratic.c +++ b/src/algs/mma/ccsa_quadratic.c @@ -438,13 +438,15 @@ nlopt_result ccsa_quadratic_minimize( gi(m, dd.gcval, n, xcur, NULL, &dd); } +#ifndef CRAN_COMPATIBILITY if (verbose) { - printf("CCSA dual converged in %d iters to g=%g:\n", - dd.count, dd.gval); - for (i = 0; i < MIN(verbose, m); ++i) - printf(" CCSA y[%u]=%g, gc[%u]=%g\n", - i, y[i], i, dd.gcval[i]); + printf("CCSA dual converged in %d iters to g=%g:\n", + dd.count, dd.gval); + for (i = 0; i < MIN(verbose, m); ++i) + printf(" CCSA y[%u]=%g, gc[%u]=%g\n", + i, y[i], i, dd.gcval[i]); } +#endif fcur = f(n, xcur, dfdx_cur, f_data); ++ *(stop->nevals_p); @@ -476,8 +478,10 @@ nlopt_result ccsa_quadratic_minimize( if ((fcur < *minf && (inner_done || feasible_cur || !feasible)) || (!feasible && infeasibility_cur < infeasibility)) { - if (verbose && !feasible_cur) - printf("CCSA - using infeasible point?\n"); +#ifndef CRAN_COMPATIBILITY + if (verbose && !feasible_cur) + printf("CCSA - using infeasible point?\n"); +#endif dd.fval = *minf = fcur; infeasibility = infeasibility_cur; memcpy(fcval, fcval_cur, sizeof(double)*m); @@ -517,10 +521,13 @@ nlopt_result ccsa_quadratic_minimize( 1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i]) / dd.wval)); - if (verbose) - printf("CCSA inner iteration: rho -> %g\n", rho); - for (i = 0; i < MIN(verbose, m); ++i) - printf(" CCSA rhoc[%u] -> %g\n", i,rhoc[i]); +#ifndef CRAN_COMPATIBILITY + if (verbose) { + printf("CCSA inner iteration: rho -> %g\n", rho); + for (i = 0; i < MIN(verbose, m); ++i) + printf(" CCSA rhoc[%u] -> %g\n", i,rhoc[i]); + } +#endif } if (nlopt_stop_ftol(stop, fcur, fprev)) @@ -531,12 +538,16 @@ nlopt_result ccsa_quadratic_minimize( /* update rho and sigma for iteration k+1 */ rho = MAX(0.1 * rho, CCSA_RHOMIN); +#ifndef CRAN_COMPATIBILITY if (verbose) printf("CCSA outer iteration: rho -> %g\n", rho); +#endif for (i = 0; i < m; ++i) rhoc[i] = MAX(0.1 * rhoc[i], CCSA_RHOMIN); +#ifndef CRAN_COMPATIBILITY for (i = 0; i < MIN(verbose, m); ++i) printf(" CCSA rhoc[%u] -> %g\n", i, rhoc[i]); +#endif if (k > 1) { for (j = 0; j < n; ++j) { double dx2 = (xcur[j]-xprev[j]) * (xprev[j]-xprevprev[j]); @@ -549,9 +560,11 @@ nlopt_result ccsa_quadratic_minimize( sigma[j] = MAX(sigma[j], 1e-8*(ub[j]-lb[j])); } } +#ifndef CRAN_COMPATIBILITY for (j = 0; j < MIN(verbose, n); ++j) - printf(" CCSA sigma[%u] -> %g\n", - j, sigma[j]); + printf(" CCSA sigma[%u] -> %g\n", + j, sigma[j]); +#endif } } diff --git a/src/algs/mma/mma.c b/src/algs/mma/mma.c index 3236099c8..d354a9743 100644 --- a/src/algs/mma/mma.c +++ b/src/algs/mma/mma.c @@ -284,13 +284,15 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, } dual_func(m, y, NULL, &dd); /* evaluate final xcur etc. */ +#ifndef CRAN_COMPATIBILITY if (verbose) { - printf("MMA dual converged in %d iterations to g=%g:\n", - dd.count, dd.gval); - for (i = 0; i < MIN(verbose, m); ++i) - printf(" MMA y[%u]=%g, gc[%u]=%g\n", - i, y[i], i, dd.gcval[i]); + printf("MMA dual converged in %d iterations to g=%g:\n", + dd.count, dd.gval); + for (i = 0; i < MIN(verbose, m); ++i) + printf(" MMA y[%u]=%g, gc[%u]=%g\n", + i, y[i], i, dd.gcval[i]); } +#endif fcur = f(n, xcur, dfdx_cur, f_data); ++ *(stop->nevals_p); @@ -327,8 +329,10 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, if ((fcur < *minf && (inner_done || feasible_cur || !feasible)) || (!feasible && infeasibility_cur < infeasibility)) { - if (verbose && !feasible_cur) - printf("MMA - using infeasible point?\n"); +#ifndef CRAN_COMPATIBILITY + if (verbose && !feasible_cur) + printf("MMA - using infeasible point?\n"); +#endif dd.fval = *minf = fcur; infeasibility = infeasibility_cur; memcpy(fcval, fcval_cur, sizeof(double)*m); @@ -369,10 +373,13 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, 1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i]) / dd.wval)); - if (verbose) - printf("MMA inner iteration: rho -> %g\n", rho); - for (i = 0; i < MIN(verbose, m); ++i) - printf(" MMA rhoc[%u] -> %g\n", i,rhoc[i]); +#ifndef CRAN_COMPATIBILITY + if (verbose) { + printf("MMA inner iteration: rho -> %g\n", rho); + for (i = 0; i < MIN(verbose, m); ++i) + printf(" MMA rhoc[%u] -> %g\n", i,rhoc[i]); + } +#endif } if (nlopt_stop_ftol(stop, fcur, fprev)) @@ -383,12 +390,16 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, /* update rho and sigma for iteration k+1 */ rho = MAX(0.1 * rho, MMA_RHOMIN); +#ifndef CRAN_COMPATIBILITY if (verbose) - printf("MMA outer iteration: rho -> %g\n", rho); + printf("MMA outer iteration: rho -> %g\n", rho); +#endif for (i = 0; i < m; ++i) rhoc[i] = MAX(0.1 * rhoc[i], MMA_RHOMIN); +#ifndef CRAN_COMPATIBILITY for (i = 0; i < MIN(verbose, m); ++i) - printf(" MMA rhoc[%u] -> %g\n", i, rhoc[i]); + printf(" MMA rhoc[%u] -> %g\n", i, rhoc[i]); +#endif if (k > 1) { for (j = 0; j < n; ++j) { double dx2 = (xcur[j]-xprev[j]) * (xprev[j]-xprevprev[j]); @@ -399,9 +410,11 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, sigma[j] = MAX(sigma[j], 0.01*(ub[j]-lb[j])); } } +#ifndef CRAN_COMPATIBILITY for (j = 0; j < MIN(verbose, n); ++j) - printf(" MMA sigma[%u] -> %g\n", - j, sigma[j]); + printf(" MMA sigma[%u] -> %g\n", + j, sigma[j]); +#endif } } diff --git a/src/algs/neldermead/sbplx.c b/src/algs/neldermead/sbplx.c index b748e3081..78bcc2e12 100644 --- a/src/algs/neldermead/sbplx.c +++ b/src/algs/neldermead/sbplx.c @@ -7,17 +7,17 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include @@ -87,7 +87,7 @@ nlopt_result sbplx_minimize(int n, nlopt_func f, void *f_data, + (nsmax+1)*(nsmax+1)+2*nsmax)); if (!xstep) return NLOPT_OUT_OF_MEMORY; xprev = xstep + n; dx = xprev + n; - xs = dx + n; xsstep = xs + nsmax; + xs = dx + n; xsstep = xs + nsmax; lbs = xsstep + nsmax; ubs = lbs + nsmax; scratch = ubs + nsmax; p = (int *) malloc(sizeof(int) * n); @@ -155,9 +155,11 @@ nlopt_result sbplx_minimize(int n, nlopt_func f, void *f_data, ret = nldrmd_minimize_(ns, subspace_func, &sd, lbs,ubs,xs, minf, xsstep, stop, psi, scratch, &fdiff); if (fdiff > fdiff_max) fdiff_max = fdiff; +#ifndef CRAN_COMPATIBILITY if (sbplx_verbose) - printf("%d NM iterations for (%d,%d) subspace\n", - *(stop->nevals_p) - nevals, sd.is, ns); + printf("%d NM iterations for (%d,%d) subspace\n", + *(stop->nevals_p) - nevals, sd.is, ns); +#endif for (k = i; k < i+ns; ++k) x[p[k]] = xs[k-i]; if (ret == NLOPT_FAILURE) { ret=NLOPT_XTOL_REACHED; goto done; } if (ret != NLOPT_XTOL_REACHED) goto done; @@ -176,9 +178,11 @@ nlopt_result sbplx_minimize(int n, nlopt_func f, void *f_data, ret = nldrmd_minimize_(ns, subspace_func, &sd, lbs,ubs,xs, minf, xsstep, stop, psi, scratch, &fdiff); if (fdiff > fdiff_max) fdiff_max = fdiff; +#ifndef CRAN_COMPATIBILITY if (sbplx_verbose) - printf("sbplx: %d NM iterations for (%d,%d) subspace\n", - *(stop->nevals_p) - nevals, sd.is, ns); + printf("sbplx: %d NM iterations for (%d,%d) subspace\n", + *(stop->nevals_p) - nevals, sd.is, ns); +#endif for (i = sd.is; i < n; ++i) x[p[i]] = xs[i-sd.is]; if (ret == NLOPT_FAILURE) { ret=NLOPT_XTOL_REACHED; goto done; } if (ret != NLOPT_XTOL_REACHED) goto done; @@ -222,9 +226,11 @@ nlopt_result sbplx_minimize(int n, nlopt_func f, void *f_data, if (scale < omega) scale = omega; if (scale > 1/omega) scale = 1/omega; } +#ifndef CRAN_COMPATIBILITY if (sbplx_verbose) - printf("sbplx: stepsize scale factor = %g\n", scale); - for (i = 0; i < n; ++i) + printf("sbplx: stepsize scale factor = %g\n", scale); +#endif + for (i = 0; i < n; ++i) xstep[i] = (dx[i] == 0) ? -(xstep[i] * scale) : copysign(xstep[i] * scale, dx[i]); } From 09a49c6f01085755c56aae569e9ae74327c99960 Mon Sep 17 00:00:00 2001 From: Aymeric Stamm Date: Tue, 22 Apr 2025 16:39:18 +0200 Subject: [PATCH 3/3] Added FindR.cmake to properly use R C API for printing and error handling. --- CMakeLists.txt | 14 ++-- cmake/FindR.cmake | 99 +++++++++++++++++++++++++ src/algs/auglag/auglag.c | 29 ++++++-- src/algs/cobyla/cobyla.c | 115 ++++++++++++++++++++++++++---- src/algs/direct/direct-internal.h | 4 +- src/algs/mma/ccsa_quadratic.c | 39 ++++++++-- src/algs/mma/mma.c | 39 ++++++++-- src/algs/neldermead/sbplx.c | 17 ++++- src/api/nlopt-internal.h | 2 +- src/api/optimize.c | 12 +++- src/util/nlopt-util.h | 7 +- src/util/stop.c | 10 ++- 12 files changed, 341 insertions(+), 46 deletions(-) create mode 100644 cmake/FindR.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 22d64187d..7a847abae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,18 +46,15 @@ option (NLOPT_JAVA "build java bindings" ON) option (NLOPT_SWIG "use SWIG to build bindings" ON) option (NLOPT_LUKSAN "enable LGPL Luksan solvers" ON) option (NLOPT_TESTS "build unit tests" OFF) -option (USE_R_COMPATIBILITY "compile with R compatibility functions only" OFF) if (NLOPT_FORTRAN) enable_language (Fortran) endif () -if (USE_R_COMPATIBILITY) - add_definitions(-DCRAN_COMPATIBILITY) -endif () - include (GNUInstallDirs) +set (NLOPT_R_BINDIR "" CACHE STRING "Directory containing the R executable") + # Offer the user the choice of overriding the installation directories set (NLOPT_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING "Installation directory for libraries") set (NLOPT_INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR} CACHE STRING "Installation directory for executables") @@ -244,6 +241,13 @@ if (NLOPT_LUKSAN) target_include_directories(${nlopt_lib} PRIVATE src/algs/luksan) target_compile_definitions (${nlopt_lib} PRIVATE NLOPT_LUKSAN) endif () + +if (NOT "${NLOPT_R_BINDIR}" STREQUAL "") + find_package(R REQUIRED) + target_include_directories(${nlopt_lib} PRIVATE ${R_INCLUDE_DIR}) + target_compile_definitions(${nlopt_lib} PRIVATE NLOPT_R) +endif () + if (M_LIBRARY) target_link_libraries (${nlopt_lib} ${M_LIBRARY}) endif () diff --git a/cmake/FindR.cmake b/cmake/FindR.cmake new file mode 100644 index 000000000..efdbc5411 --- /dev/null +++ b/cmake/FindR.cmake @@ -0,0 +1,99 @@ +# Adapted from +# https://github.com/CoolProp/CoolProp/blob/master/dev/cmake/Modules/FindR.cmake +# which is MIT-licensed + +# - Find R +# This module finds the libraries corresponding to the R program +# It is based on the code from http://github.com/usnistgov/REFPROP-wrappers +# which is in the public domain + +# This code sets the following variables: +# +# R_LIBRARY - path to the R shared library +# R_INCLUDE_DIR - include directory(ies) +# R_BIN_DIR - directory that contains the R executable being used + +include(FindPackageHandleStandardArgs) + +SET(R_FOUND 0) + +IF( "${NLOPT_R_BINDIR}" STREQUAL "") + MESSAGE(FATAL_ERROR "You must pass the CMake variable NLOPT_R_BINDIR pointing to the directory that contains your executable") +ENDIF() + +find_program(R_EXEC + NAMES R + PATHS ${NLOPT_R_BINDIR} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH + NO_DEFAULT_PATH + NO_CMAKE_PATH + ) +IF( "${R_EXEC}" STREQUAL "R_EXEC-NOTFOUND") + MESSAGE(FATAL_ERROR "The executable R could not be found in the folder ${NLOPT_R_BINDIR}") +ENDIF() + +MESSAGE(STATUS "R_EXEC= ${R_EXEC}") +# Parse the output of the R path command, removing whitespace +FUNCTION(chomp arg1 arg2) + string(REPLACE "\n" ";" arg1list ${arg1}) + list(GET arg1list 1 arg1line) + string(LENGTH ${arg1line} len) + MATH(EXPR length ${len}-6) + string(SUBSTRING ${arg1line} 5 ${length} arg1path) + # see http://www.cmake.org/pipermail/cmake/2008-November/025423.html + set(${arg2} ${arg1path} PARENT_SCOPE) +ENDFUNCTION(chomp) + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/get_home.R R.home()) +execute_process( + COMMAND ${R_EXEC} --quiet -f ${CMAKE_CURRENT_BINARY_DIR}/get_home.R OUTPUT_VARIABLE R_HOME_TEXT RESULT_VARIABLE R_HOME_RESULT +) +file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/get_home.R) +chomp(${R_HOME_TEXT} R_HOME_TEXT) +MESSAGE(STATUS "R_HOME_TEXT = ${R_HOME_TEXT} w/ RESULT=${R_HOME_RESULT}") + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/get_include.R R.home(component=\"include\")) +execute_process( + COMMAND ${R_EXEC} --quiet -f ${CMAKE_CURRENT_BINARY_DIR}/get_include.R OUTPUT_VARIABLE R_INCLUDE_TEXT RESULT_VARIABLE R_INCLUDE_RESULT +) +file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/get_include.R) +chomp(${R_INCLUDE_TEXT} R_INCLUDE_DIR) +MESSAGE(STATUS "R_INCLUDE = ${R_INCLUDE_DIR} w/ RESULT=${R_INCLUDE_RESULT}") + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/get_bin.R R.home(component=\"bin\")) +execute_process( + COMMAND ${R_EXEC} --quiet -f ${CMAKE_CURRENT_BINARY_DIR}/get_bin.R OUTPUT_VARIABLE R_BIN_TEXT RESULT_VARIABLE R_BIN_RESULT +) +file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/get_bin.R) +chomp(${R_BIN_TEXT} R_BIN_DIR) +MESSAGE(STATUS "R_BIN_TEXT = ${R_BIN_DIR} w/ RESULT=${R_BIN_RESULT}") + +if (WIN32) +# Bug in cmake 3.17, need to search for file rather than library +find_file( + R_LIBRARY + NAMES R.dll + PATHS ${R_BIN_DIR} + NO_DEFAULT_PATH +) +else() +set(R_PATH_LOC "${R_HOME_TEXT}/lib") +MESSAGE(STATUS "R_PATH_LOC = ${R_PATH_LOC}") +find_library( + R_LIBRARY + NAMES R + PATHS ${R_PATH_LOC} + NO_DEFAULT_PATH + ) +endif() +MESSAGE(STATUS "R_LIBRARY = ${R_LIBRARY}") + +find_package_handle_standard_args(R DEFAULT_MSG + R_LIBRARY R_INCLUDE_DIR) + +MARK_AS_ADVANCED( + R_BIN_DIR + R_LIBRARY + R_INCLUDE_DIR +) diff --git a/src/algs/auglag/auglag.c b/src/algs/auglag/auglag.c index 9682429e0..3e634c990 100644 --- a/src/algs/auglag/auglag.c +++ b/src/algs/auglag/auglag.c @@ -179,15 +179,21 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, else d.rho = 1; /* whatever, doesn't matter */ -#ifndef CRAN_COMPATIBILITY if (auglag_verbose) { +#ifndef NLOPT_R printf("auglag: initial rho=%g\nauglag initial lambda=", d.rho); for (i = 0; i < d.pp; ++i) printf(" %g", d.lambda[i]); printf("\nauglag initial mu = "); for (i = 0; i < d.mm; ++i) printf(" %g", d.mu[i]); printf("\n"); - } +#else + Rprintf("auglag: initial rho=%g\nauglag initial lambda=", d.rho); + for (i = 0; i < d.pp; ++i) Rprintf(" %g", d.lambda[i]); + Rprintf("\nauglag initial mu = "); + for (i = 0; i < d.mm; ++i) Rprintf(" %g", d.mu[i]); + Rprintf("\n"); #endif + } do { double prev_ICM = ICM; @@ -196,9 +202,11 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, stop->maxeval - *(stop->nevals_p), stop->maxtime - (nlopt_seconds() - stop->start)); -#ifndef CRAN_COMPATIBILITY if (auglag_verbose) +#ifndef NLOPT_R printf("auglag: subopt return code %d\n", ret); +#else + Rprintf("auglag: subopt return code %d\n", ret); #endif if (ret < 0) break; @@ -206,9 +214,11 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, fcur = f(n, xcur, NULL, f_data); if (nlopt_stop_forced(stop)) { ret = NLOPT_FORCED_STOP; goto done; } -#ifndef CRAN_COMPATIBILITY if (auglag_verbose) +#ifndef NLOPT_R printf("auglag: fcur = %g\n", fcur); +#else + Rprintf("auglag: fcur = %g\n", fcur); #endif ICM = 0; @@ -246,7 +256,7 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, auglag_iters++; -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (auglag_verbose) { printf("auglag %d: ICM=%g (%sfeasible), rho=%g\nauglag lambda=", auglag_iters, ICM, feasible ? "" : "not ", d.rho); @@ -255,6 +265,15 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data, for (i = 0; i < d.mm; ++i) printf(" %g", d.mu[i]); printf("\n"); } +#else + if (auglag_verbose) { + Rprintf("auglag %d: ICM=%g (%sfeasible), rho=%g\nauglag lambda=", + auglag_iters, ICM, feasible ? "" : "not ", d.rho); + for (i = 0; i < d.pp; ++i) Rprintf(" %g", d.lambda[i]); + Rprintf("\nauglag %d: mu = ", auglag_iters); + for (i = 0; i < d.mm; ++i) Rprintf(" %g", d.mu[i]); + Rprintf("\n"); + } #endif if ((feasible && (!minf_feasible || penalty < minf_penalty diff --git a/src/algs/cobyla/cobyla.c b/src/algs/cobyla/cobyla.c index ec3dbd94c..4225da8e0 100644 --- a/src/algs/cobyla/cobyla.c +++ b/src/algs/cobyla/cobyla.c @@ -391,16 +391,20 @@ nlopt_result cobyla(int n, int m, double *x, double *minf, double rhobeg, double if (n == 0) { -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (iprint>=1) fprintf(stderr, "cobyla: N==0.\n"); +#else + if (iprint>=1) REprintf("cobyla: N==0.\n"); #endif return NLOPT_SUCCESS; } if (n < 0 || m < 0) { -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (iprint>=1) fprintf(stderr, "cobyla: N<0 or M<0.\n"); +#else + if (iprint>=1) REprintf("cobyla: N<0 or M<0.\n"); #endif return NLOPT_INVALID_ARGS; } @@ -409,16 +413,20 @@ nlopt_result cobyla(int n, int m, double *x, double *minf, double rhobeg, double w = (double*) malloc(U(n*(3*n+2*m+11)+4*m+6)*sizeof(*w)); if (w == NULL) { -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (iprint>=1) fprintf(stderr, "cobyla: memory allocation error.\n"); +#else + if (iprint>=1) REprintf("cobyla: memory allocation error.\n"); #endif return NLOPT_OUT_OF_MEMORY; } iact = (int*)malloc(U(m+1)*sizeof(*iact)); if (iact == NULL) { -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (iprint>=1) fprintf(stderr, "cobyla: memory allocation error.\n"); +#else + if (iprint>=1) REprintf("cobyla: memory allocation error.\n"); #endif free(w); return NLOPT_OUT_OF_MEMORY; @@ -538,12 +546,17 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, delta = 1.1; rho = *rhobeg; parmu = 0.; -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (*iprint >= 2) { fprintf(stderr, "cobyla: the initial value of RHO is %12.6E and PARMU is set to zero.\n", rho); } +#else + if (*iprint >= 2) { + REprintf("cobyla: the initial value of RHO is %12.6E and PARMU is set to zero.\n", + rho); + } #endif temp = 1. / rho; i__1 = *n; @@ -591,10 +604,14 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, ++ *(stop->nevals_p); if (calcfc(*n, *m, &x[1], &f, &con[1], state)) { -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (*iprint >= 1) { fprintf(stderr, "cobyla: user requested end of minimization.\n"); } +#else + if (*iprint >= 1) { + REprintf("cobyla: user requested end of minimization.\n"); + } #endif rc = NLOPT_FORCED_STOP; goto L600; @@ -618,7 +635,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, goto L620; /* not L600 because we want to use current x, f, resmax */ } -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (*(stop->nevals_p) == *iprint - 1 || *iprint == 3) { fprintf(stderr, "cobyla: NFVALS = %4d, F =%13.6E, MAXCV =%13.6E\n", *(stop->nevals_p), f, resmax); @@ -637,6 +654,25 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } fprintf(stderr, "\n"); } +#else + if (*(stop->nevals_p) == *iprint - 1 || *iprint == 3) { + REprintf("cobyla: NFVALS = %4d, F =%13.6E, MAXCV =%13.6E\n", + *(stop->nevals_p), f, resmax); + i__1 = iptem; + REprintf("cobyla: X ="); + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__>1) REprintf(" "); + REprintf("%13.6E", x[i__]); + } + if (iptem < *n) { + i__1 = *n; + for (i__ = iptemp; i__ <= i__1; ++i__) { + if (!((i__-1) % 4)) REprintf("\ncobyla: "); + REprintf("%15.6E", x[i__]); + } + } + REprintf("\n"); + } #endif con[mp] = f; con[*mpp] = resmax; @@ -767,10 +803,14 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } } if (error > .1) { -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (*iprint >= 1) { fprintf(stderr, "cobyla: rounding errors are becoming damaging.\n"); } +#else + if (*iprint >= 1) { + REprintf("cobyla: rounding errors are becoming damaging.\n"); + } #endif rc = NLOPT_ROUNDOFF_LIMITED; goto L600; @@ -994,10 +1034,14 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } if (parmu < barmu * 1.5) { parmu = barmu * 2.; -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (*iprint >= 2) { fprintf(stderr, "cobyla: increase in PARMU to %12.6E\n", parmu); } +#else + if (*iprint >= 2) { + REprintf("cobyla: increase in PARMU to %12.6E\n", parmu); + } #endif phi = datmat[mp + np * datmat_dim1] + parmu * datmat[*mpp + np * datmat_dim1]; @@ -1195,7 +1239,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, parmu = (cmax - cmin) / denom; } } -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (*iprint >= 2) { fprintf(stderr, "cobyla: reduction in RHO to %12.6E and PARMU =%13.6E\n", rho, parmu); @@ -1219,6 +1263,30 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } fprintf(stderr, "\n"); } +#else + if (*iprint >= 2) { + REprintf("cobyla: reduction in RHO to %12.6E and PARMU =%13.6E\n", + rho, parmu); + } + if (*iprint == 2) { + REprintf("cobyla: NFVALS = %4d, F =%13.6E, MAXCV =%13.6E\n", + *(stop->nevals_p), datmat[mp + np * datmat_dim1], datmat[*mpp + np * datmat_dim1]); + + REprintf("cobyla: X ="); + i__1 = iptem; + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__>1) REprintf(" "); + REprintf("%13.6E", sim[i__ + np * sim_dim1]); + } + if (iptem < *n) { + i__1 = *n; + for (i__ = iptemp; i__ <= i__1; ++i__) { + if (!((i__-1) % 4)) REprintf("\ncobyla: "); + REprintf("%15.6E", x[i__]); + } + } + REprintf("\n"); + } #endif goto L140; } @@ -1227,10 +1295,14 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, /* Return the best calculated values of the variables. */ -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (*iprint >= 1) { fprintf(stderr, "cobyla: normal return.\n"); } +#else + if (*iprint >= 1) { + REprintf("cobyla: normal return.\n"); + } #endif if (ifull == 1) { goto L620; @@ -1244,7 +1316,7 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, resmax = datmat[*mpp + np * datmat_dim1]; L620: *minf = f; -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (*iprint >= 1) { fprintf(stderr, "cobyla: NFVALS = %4d, F =%13.6E, MAXCV =%13.6E\n", *(stop->nevals_p), f, resmax); @@ -1263,6 +1335,25 @@ static nlopt_result cobylb(int *n, int *m, int *mpp, } fprintf(stderr, "\n"); } +#else + if (*iprint >= 1) { + REprintf("cobyla: NFVALS = %4d, F =%13.6E, MAXCV =%13.6E\n", + *(stop->nevals_p), f, resmax); + i__1 = iptem; + REprintf("cobyla: X ="); + for (i__ = 1; i__ <= i__1; ++i__) { + if (i__>1) REprintf(" "); + REprintf("%13.6E", x[i__]); + } + if (iptem < *n) { + i__1 = *n; + for (i__ = iptemp; i__ <= i__1; ++i__) { + if (!((i__-1) % 4)) REprintf("\ncobyla: "); + REprintf("%15.6E", x[i__]); + } + } + REprintf("\n"); + } #endif return rc; } /* cobylb */ diff --git a/src/algs/direct/direct-internal.h b/src/algs/direct/direct-internal.h index 3a1240a61..fa12c9320 100644 --- a/src/algs/direct/direct-internal.h +++ b/src/algs/direct/direct-internal.h @@ -17,10 +17,10 @@ typedef int integer; typedef double doublereal; typedef direct_objective_func fp; -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R #define ASRT(c) if (!(c)) { fprintf(stderr, "DIRECT assertion failure at " __FILE__ ":%d -- " #c "\n", __LINE__); exit(EXIT_FAILURE); } #else -#define ASRT(c) if (!(c)) { } +#define ASRT(c) if (!(c)) { Rf_error("DIRECT assertion failure at " __FILE__ ":%d -- " #c "\n", __LINE__); } #endif #define MIN(a,b) ((a) < (b) ? (a) : (b)) diff --git a/src/algs/mma/ccsa_quadratic.c b/src/algs/mma/ccsa_quadratic.c index 771bd620f..1edc4936a 100644 --- a/src/algs/mma/ccsa_quadratic.c +++ b/src/algs/mma/ccsa_quadratic.c @@ -438,7 +438,7 @@ nlopt_result ccsa_quadratic_minimize( gi(m, dd.gcval, n, xcur, NULL, &dd); } -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (verbose) { printf("CCSA dual converged in %d iters to g=%g:\n", dd.count, dd.gval); @@ -446,6 +446,14 @@ nlopt_result ccsa_quadratic_minimize( printf(" CCSA y[%u]=%g, gc[%u]=%g\n", i, y[i], i, dd.gcval[i]); } +#else + if (verbose) { + Rprintf("CCSA dual converged in %d iters to g=%g:\n", + dd.count, dd.gval); + for (i = 0; i < MIN(verbose, m); ++i) + Rprintf(" CCSA y[%u]=%g, gc[%u]=%g\n", + i, y[i], i, dd.gcval[i]); + } #endif fcur = f(n, xcur, dfdx_cur, f_data); @@ -478,9 +486,12 @@ nlopt_result ccsa_quadratic_minimize( if ((fcur < *minf && (inner_done || feasible_cur || !feasible)) || (!feasible && infeasibility_cur < infeasibility)) { -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (verbose && !feasible_cur) printf("CCSA - using infeasible point?\n"); +#else + if (verbose && !feasible_cur) + Rprintf("CCSA - using infeasible point?\n"); #endif dd.fval = *minf = fcur; infeasibility = infeasibility_cur; @@ -521,12 +532,18 @@ nlopt_result ccsa_quadratic_minimize( 1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i]) / dd.wval)); -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (verbose) { printf("CCSA inner iteration: rho -> %g\n", rho); for (i = 0; i < MIN(verbose, m); ++i) printf(" CCSA rhoc[%u] -> %g\n", i,rhoc[i]); } +#else + if (verbose) { + Rprintf("CCSA inner iteration: rho -> %g\n", rho); + for (i = 0; i < MIN(verbose, m); ++i) + Rprintf(" CCSA rhoc[%u] -> %g\n", i,rhoc[i]); + } #endif } @@ -538,15 +555,21 @@ nlopt_result ccsa_quadratic_minimize( /* update rho and sigma for iteration k+1 */ rho = MAX(0.1 * rho, CCSA_RHOMIN); -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (verbose) printf("CCSA outer iteration: rho -> %g\n", rho); +#else + if (verbose) + Rprintf("CCSA outer iteration: rho -> %g\n", rho); #endif for (i = 0; i < m; ++i) rhoc[i] = MAX(0.1 * rhoc[i], CCSA_RHOMIN); -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R for (i = 0; i < MIN(verbose, m); ++i) printf(" CCSA rhoc[%u] -> %g\n", i, rhoc[i]); +#else + for (i = 0; i < MIN(verbose, m); ++i) + Rprintf(" CCSA rhoc[%u] -> %g\n", i, rhoc[i]); #endif if (k > 1) { for (j = 0; j < n; ++j) { @@ -560,10 +583,14 @@ nlopt_result ccsa_quadratic_minimize( sigma[j] = MAX(sigma[j], 1e-8*(ub[j]-lb[j])); } } -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R for (j = 0; j < MIN(verbose, n); ++j) printf(" CCSA sigma[%u] -> %g\n", j, sigma[j]); +#else + for (j = 0; j < MIN(verbose, n); ++j) + Rprintf(" CCSA sigma[%u] -> %g\n", + j, sigma[j]); #endif } } diff --git a/src/algs/mma/mma.c b/src/algs/mma/mma.c index d354a9743..d100c1e25 100644 --- a/src/algs/mma/mma.c +++ b/src/algs/mma/mma.c @@ -284,7 +284,7 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, } dual_func(m, y, NULL, &dd); /* evaluate final xcur etc. */ -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (verbose) { printf("MMA dual converged in %d iterations to g=%g:\n", dd.count, dd.gval); @@ -292,6 +292,14 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, printf(" MMA y[%u]=%g, gc[%u]=%g\n", i, y[i], i, dd.gcval[i]); } +#else + if (verbose) { + Rprintf("MMA dual converged in %d iterations to g=%g:\n", + dd.count, dd.gval); + for (i = 0; i < MIN(verbose, m); ++i) + Rprintf(" MMA y[%u]=%g, gc[%u]=%g\n", + i, y[i], i, dd.gcval[i]); + } #endif fcur = f(n, xcur, dfdx_cur, f_data); @@ -329,9 +337,12 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, if ((fcur < *minf && (inner_done || feasible_cur || !feasible)) || (!feasible && infeasibility_cur < infeasibility)) { -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (verbose && !feasible_cur) printf("MMA - using infeasible point?\n"); +#else + if (verbose && !feasible_cur) + Rprintf("MMA - using infeasible point?\n"); #endif dd.fval = *minf = fcur; infeasibility = infeasibility_cur; @@ -373,12 +384,18 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, 1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i]) / dd.wval)); -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (verbose) { printf("MMA inner iteration: rho -> %g\n", rho); for (i = 0; i < MIN(verbose, m); ++i) printf(" MMA rhoc[%u] -> %g\n", i,rhoc[i]); } +#else + if (verbose) { + Rprintf("MMA inner iteration: rho -> %g\n", rho); + for (i = 0; i < MIN(verbose, m); ++i) + Rprintf(" MMA rhoc[%u] -> %g\n", i,rhoc[i]); + } #endif } @@ -390,15 +407,21 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, /* update rho and sigma for iteration k+1 */ rho = MAX(0.1 * rho, MMA_RHOMIN); -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (verbose) printf("MMA outer iteration: rho -> %g\n", rho); +#else + if (verbose) + Rprintf("MMA outer iteration: rho -> %g\n", rho); #endif for (i = 0; i < m; ++i) rhoc[i] = MAX(0.1 * rhoc[i], MMA_RHOMIN); -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R for (i = 0; i < MIN(verbose, m); ++i) printf(" MMA rhoc[%u] -> %g\n", i, rhoc[i]); +#else + for (i = 0; i < MIN(verbose, m); ++i) + Rprintf(" MMA rhoc[%u] -> %g\n", i, rhoc[i]); #endif if (k > 1) { for (j = 0; j < n; ++j) { @@ -410,10 +433,14 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data, sigma[j] = MAX(sigma[j], 0.01*(ub[j]-lb[j])); } } -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R for (j = 0; j < MIN(verbose, n); ++j) printf(" MMA sigma[%u] -> %g\n", j, sigma[j]); +#else + for (j = 0; j < MIN(verbose, n); ++j) + Rprintf(" MMA sigma[%u] -> %g\n", + j, sigma[j]); #endif } } diff --git a/src/algs/neldermead/sbplx.c b/src/algs/neldermead/sbplx.c index 78bcc2e12..54055dc1a 100644 --- a/src/algs/neldermead/sbplx.c +++ b/src/algs/neldermead/sbplx.c @@ -155,10 +155,14 @@ nlopt_result sbplx_minimize(int n, nlopt_func f, void *f_data, ret = nldrmd_minimize_(ns, subspace_func, &sd, lbs,ubs,xs, minf, xsstep, stop, psi, scratch, &fdiff); if (fdiff > fdiff_max) fdiff_max = fdiff; -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (sbplx_verbose) printf("%d NM iterations for (%d,%d) subspace\n", *(stop->nevals_p) - nevals, sd.is, ns); +#else + if (sbplx_verbose) + Rprintf("%d NM iterations for (%d,%d) subspace\n", + *(stop->nevals_p) - nevals, sd.is, ns); #endif for (k = i; k < i+ns; ++k) x[p[k]] = xs[k-i]; if (ret == NLOPT_FAILURE) { ret=NLOPT_XTOL_REACHED; goto done; } @@ -178,10 +182,14 @@ nlopt_result sbplx_minimize(int n, nlopt_func f, void *f_data, ret = nldrmd_minimize_(ns, subspace_func, &sd, lbs,ubs,xs, minf, xsstep, stop, psi, scratch, &fdiff); if (fdiff > fdiff_max) fdiff_max = fdiff; -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (sbplx_verbose) printf("sbplx: %d NM iterations for (%d,%d) subspace\n", *(stop->nevals_p) - nevals, sd.is, ns); +#else + if (sbplx_verbose) + Rprintf("sbplx: %d NM iterations for (%d,%d) subspace\n", + *(stop->nevals_p) - nevals, sd.is, ns); #endif for (i = sd.is; i < n; ++i) x[p[i]] = xs[i-sd.is]; if (ret == NLOPT_FAILURE) { ret=NLOPT_XTOL_REACHED; goto done; } @@ -226,9 +234,12 @@ nlopt_result sbplx_minimize(int n, nlopt_func f, void *f_data, if (scale < omega) scale = omega; if (scale > 1/omega) scale = 1/omega; } -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (sbplx_verbose) printf("sbplx: stepsize scale factor = %g\n", scale); +#else + if (sbplx_verbose) + Rprintf("sbplx: stepsize scale factor = %g\n", scale); #endif for (i = 0; i < n; ++i) xstep[i] = (dx[i] == 0) ? -(xstep[i] * scale) diff --git a/src/api/nlopt-internal.h b/src/api/nlopt-internal.h index 9d660c628..749667f40 100644 --- a/src/api/nlopt-internal.h +++ b/src/api/nlopt-internal.h @@ -107,7 +107,7 @@ extern "C" { extern const char *nlopt_set_errmsg(nlopt_opt opt, const char *format, ...) #ifdef __GNUC__ -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R __attribute__ ((format(printf, 2, 3))) #endif #endif diff --git a/src/api/optimize.c b/src/api/optimize.c index 45170e047..9c84dfd62 100644 --- a/src/api/optimize.c +++ b/src/api/optimize.c @@ -717,8 +717,10 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) #ifdef NLOPT_LUKSAN return luksan_plis(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage, nlopt_get_param(opt, "tolg", 0.)); #else -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R printf("ERROR - attempting to use NLOPT_LD_LBFGS, but Luksan code disabled\n"); +#else + Rprintf("ERROR - attempting to use NLOPT_LD_LBFGS, but Luksan code disabled\n"); #endif return NLOPT_INVALID_ARGS; #endif @@ -728,8 +730,10 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) #ifdef NLOPT_LUKSAN return luksan_plip(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage, algorithm == NLOPT_LD_VAR1 ? 1 : 2, nlopt_get_param(opt, "tolg", 0.)); #else -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R printf("ERROR - attempting to use NLOPT_LD_VAR*, but Luksan code disabled\n"); +#else + Rprintf("ERROR - attempting to use NLOPT_LD_VAR*, but Luksan code disabled\n"); #endif return NLOPT_INVALID_ARGS; #endif @@ -741,8 +745,10 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) #ifdef NLOPT_LUKSAN return luksan_pnet(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage, 1 + (algorithm - NLOPT_LD_TNEWTON) % 2, 1 + (algorithm - NLOPT_LD_TNEWTON) / 2, nlopt_get_param(opt, "tolg", 0.)); #else -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R printf("ERROR - attempting to use NLOPT_LD_TNEWTON*, but Luksan code disabled\n"); +#else + Rprintf("ERROR - attempting to use NLOPT_LD_TNEWTON*, but Luksan code disabled\n"); #endif return NLOPT_INVALID_ARGS; #endif diff --git a/src/util/nlopt-util.h b/src/util/nlopt-util.h index ef1f6db72..18ecae58a 100644 --- a/src/util/nlopt-util.h +++ b/src/util/nlopt-util.h @@ -30,6 +30,11 @@ #include "nlopt.h" +#ifdef NLOPT_R +#include +#include +#endif + /* workaround for Solaris + gcc 3.4.x bug (see configure.ac) */ #if defined(__GNUC__) && defined(REPLACEMENT_HUGE_VAL) # undef HUGE_VAL @@ -104,7 +109,7 @@ extern "C" { extern char *nlopt_vsprintf(char *p, const char *format, va_list ap); extern void nlopt_stop_msg(const nlopt_stopping * s, const char *format, ...) #ifdef __GNUC__ -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R __attribute__ ((format(printf, 2, 3))) #endif #endif diff --git a/src/util/stop.c b/src/util/stop.c index dc4c90f15..93ca46069 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -189,9 +189,12 @@ char *nlopt_vsprintf(char *p, const char *format, va_list ap) int ret; p = (char *) realloc(p, len); -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (!p) abort(); +#else + if (!p) + Rf_error("Memory allocation failed in nlopt_vsprintf"); #endif /* TODO: check HAVE_VSNPRINTF, and fallback to vsprintf otherwise */ @@ -200,9 +203,12 @@ char *nlopt_vsprintf(char *p, const char *format, va_list ap) if the buffer is too small; older versions (e.g. MS) return -1 */ len = ret >= 0 ? (size_t) (ret + 1) : (len * 3) >> 1; p = (char *) realloc(p, len); -#ifndef CRAN_COMPATIBILITY +#ifndef NLOPT_R if (!p) abort(); +#else + if (!p) + Rf_error("Memory allocation failed in nlopt_vsprintf"); #endif } return p;