├── .github ├── dependabot.yml └── workflows │ ├── publish.yml │ └── tests.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE.md ├── README.md ├── cobyla ├── CMakeLists.txt ├── README.md ├── cobyla.c ├── cobyla.h ├── cobyla.rs ├── compile_commands.json └── nlopt │ ├── CMakeLists.txt │ ├── README.md │ ├── cobyla.c │ ├── cobyla.h │ ├── cobyla.rs │ ├── compile_commands.json │ ├── nlopt-util.h │ ├── nlopt.h │ ├── nlopt_config.h │ ├── nlopt_config.h.in │ ├── rescale.c │ ├── stop.c │ └── timer.c ├── examples └── paraboloid.rs └── src ├── cobyla.rs ├── cobyla_solver.rs ├── cobyla_state.rs ├── lib.rs └── nlopt_cobyla.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | 9 | - package-ecosystem: cargo 10 | directory: "/" 11 | schedule: 12 | interval: daily 13 | open-pull-requests-limit: 10 -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published] 7 | 8 | jobs: 9 | publish: 10 | name: Publish 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout sources 14 | uses: actions/checkout@v5 15 | 16 | - name: Install stable toolchain 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | toolchain: stable 20 | override: true 21 | 22 | - name: Publish crates 23 | uses: katyo/publish-crates@v2 24 | with: 25 | registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} 26 | ignore-unpublished-changes: true 27 | 28 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | 8 | jobs: 9 | testing: 10 | name: testing-${{ matrix.toolchain }}-${{ matrix.os }} 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | toolchain: 15 | - stable 16 | os: 17 | - ubuntu-latest 18 | - windows-latest 19 | - macos-latest 20 | 21 | steps: 22 | - name: Checkout sources 23 | uses: actions/checkout@v5 24 | 25 | - name: Install toolchain 26 | uses: actions-rs/toolchain@v1 27 | with: 28 | profile: minimal 29 | toolchain: ${{ matrix.toolchain }} 30 | override: true 31 | 32 | - name: Run cargo test in release mode 33 | uses: actions-rs/cargo@v1 34 | with: 35 | command: test 36 | args: --all --release 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | /build -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased] 4 | 5 | ## [0.7.0] - 2025-10-04 6 | 7 | * Upgrade to argmin 0.11.0 8 | * Bump to edition 2024 9 | * Use `web-time` instead of deprecated `instant` 10 | 11 | ## [0.6.0] - 2024-04-22 12 | 13 | * Upgrade to argmin 0.10.0: 14 | * new `serde1` feature to enable serialization/deserialization (required for checkpointing) 15 | * add `argmin-observer-slog` dependency 16 | 17 | ## [0.5.1] - 2023-10-19 18 | 19 | * Fix default constraint tolerance (set to zero, was 2e-4) 20 | 21 | ## [0.5.0] - 2023-10-13 22 | 23 | * Remove `fmin_cobyla` implementation as `nlopt_cobyla` now renamed `minimize` based on NLopt implementation is more powerful 24 | Nevertheless Cobyla argmin solver is still based on initial implementation, not on NLopt one. 25 | * Remove gradient from `ObjFn` trait which is now renamed `Func` 26 | * `minimize` API rework to make it more Rusty. 27 | * Not all options of NLopt version are managed. Currently `cobyla::minimize` handles `xinit`, `bounds`, `max_eval`, `ftol_rel`, 28 | `ftol_abs`, `xtol_rel`, `xtol_abs` and only inequality contraints (like c >= 0). See documentation for further details. 29 | 30 | ## [0.4.0] - 2023-10-06 31 | 32 | COBYLA implementation coming from the NLopt project is now also available (as `nlopt_cobyla`) allowing to compare 33 | with the initial implementation (`fmin_cobyla`). This new implementation went through the same process of using c2rust 34 | transpilation from initial C implementation. 35 | 36 | ## [0.3.0] - 2023-01-28 37 | 38 | COBYLA is now also implemented as an argmin::Solver to benefit from [argmin framework](https://github.com/argmin-rs) tooling. See [example](./examples/paraboloid.rs) 39 | 40 | ## [0.2.0] - 2023-01-09 41 | 42 | COBYLA C code has been translated to Rust using [c2rust](https://github.com/immunant/c2rust) then manually edited. 43 | 44 | ## [0.1.0] - 2022-05-06 45 | 46 | Rust wrapper for COBYLA optimizer (COBYLA stands for Constrained Optimization BY Linear Approximations). 47 | COBYLA C code was copied from [here](https://github.com/emmt/Algorithms/tree/master/cobyla) and wrapped 48 | using the callback trick implemented in [nlopt-rust](https://github.com/adwhit/rust-nlopt) project. 49 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Remi Lafage "] 3 | name = "cobyla" 4 | version = "0.7.0" 5 | edition = "2024" 6 | license-file = "LICENSE.md" 7 | description = "COBYLA optimizer for Rust" 8 | readme = "README.md" 9 | repository = "https://github.com/relf/cobyla/" 10 | keywords = ["optimizer", "optimization", "constrained", "derivative-free"] 11 | categories = ["algorithms", "api-bindings", "science"] 12 | documentation = "https://docs.rs/cobyla" 13 | 14 | [features] 15 | serde1 = ["dep:serde", "argmin/serde1"] 16 | 17 | [dependencies] 18 | serde = { version = "1", features = ["derive"], optional = true } 19 | libc = "0.2" 20 | argmin-observer-slog = "0.2" 21 | argmin = "0.11" 22 | web-time = "1.1.0" 23 | 24 | [dev-dependencies] 25 | approx = "0.5" 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Copyright (c) 2020-2023 Rémi Lafage 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cobyla - a pure Rust implementation 2 | 3 | [![tests](https://github.com/relf/cobyla/workflows/tests/badge.svg)](https://github.com/relf/cobyla/actions?query=workflow%3Atests) 4 | [![crates.io](https://img.shields.io/crates/v/cobyla)](https://crates.io/crates/cobyla) 5 | [![docs](https://docs.rs/cobyla/badge.svg)](https://docs.rs/cobyla) 6 | 7 | COBYLA is an algorithm for minimizing a function of many variables. The method is derivatives-free (only the function values are needed) 8 | and take into account constraints on the variables. The algorithm is described in: 9 | 10 | > M.J.D. Powell, "A direct search optimization method that models the objective and constraint functions by linear interpolation," in 11 | > Advances in Optimization and Numerical Analysis Mathematics and Its Applications, vol. 275 (eds. Susana Gomez and Jean-Pierre Hennart), 12 | > Kluwer Academic Publishers, pp. 51-67 (1994). 13 | 14 | The algorithm comes into two flavours : 15 | * As an [argmin solver](), the Rust code was generated from the C code from [here](https://github.com/emmt/Algorithms/tree/master/cobyla) 16 | * As a function `minimize`, the Rust code was generated from the C code of the [NLopt](https://github.com/stevengj/nlopt) project (version 2.7.1) 17 | 18 | In both cases, an initial transpilation was done with [c2rust](https://github.com/immunant/c2rust) then the code was manually edited to make it work. 19 | The callback mechanismn is inspired from the Rust binding of NLopt, namely [rust-nlopt](https://github.com/adwhit/rust-nlopt) 20 | 21 | ## Example 22 | 23 | ```bash 24 | cargo run --example paraboloid 25 | ``` 26 | 27 | ## Related projects 28 | 29 | * [rust-nlopt](https://github.com/adwhit/rust-nlopt): the Rust binding of the [NLopt project](https://nlopt.readthedocs.io) 30 | * [argmin](https://github.com/argmin-rs/argmin): the pure-Rust optimization framework 31 | * [slsqp](https://github.com/relf/slsqp): a pure Rust implementation of the SLSQP algorithm. 32 | 33 | ## License 34 | 35 | The project is released under MIT License. 36 | -------------------------------------------------------------------------------- /cobyla/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0.0) 2 | project (cobyla) 3 | 4 | add_library (cobyla cobyla.c) 5 | 6 | target_include_directories (cobyla PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -------------------------------------------------------------------------------- /cobyla/README.md: -------------------------------------------------------------------------------- 1 | To generate compile commands json file required by c2rust in top directory 2 | 3 | > mkdir build 4 | > cd build 5 | > cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ../cobyla 6 | > cp compile_commands.json ../cobyla 7 | 8 | Then rust generation from C 9 | 10 | > cd ../cobyla 11 | > c2rust transpile compile_commands.json -------------------------------------------------------------------------------- /cobyla/cobyla.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cobyla.c - 3 | * 4 | * Implementation (in C) of Mike Powell's COBYLA algorithm for minimizing a 5 | * function of a few variables. The method is "derivatives free" (only the 6 | * function values are needed) and accounts for constraints on the variables. 7 | * The algorithm is described in: 8 | * 9 | * M.J.D. Powell, "A direct search optimization method that models the 10 | * objective and constraint functions by linear interpolation," in Advances 11 | * in Optimization and Numerical Analysis Mathematics and Its Applications, 12 | * vol. 275 (eds. Susana Gomez and Jean-Pierre Hennart), Kluwer Academic 13 | * Publishers, pp. 51-67 (1994). 14 | * 15 | * The present code is based on the original FORTRAN version written by Mike 16 | * Powell who kindly provides his code on demand and has been converted to C by 17 | * É. Thiébaut. 18 | * 19 | * Copyright (c) 1992, Mike Powell (FORTRAN version). 20 | * Copyright (c) 2015, Éric Thiébaut (C version). 21 | * 22 | * Rémi Lafage (2021): copied from https://github.com/emmt/Algorithms/tree/master/cobyla 23 | * cobyla() was renamed raw_cobyla() to avoid name clash with NlOpt implementation 24 | */ 25 | 26 | /* To re-use as much as the code for the reverse communication routines, we use 27 | a trick which consists in "self-including" this file with different macros 28 | (_COBYLA_PART1, _COBYLA_PART2, etc.) defined so as to skip or modify certain 29 | parts of the source file. */ 30 | #ifndef _COBYLA_PART1 31 | #define _COBYLA_PART1 1 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "cobyla.h" 40 | 41 | /* Macros to deal with single/double precision. */ 42 | #undef REAL 43 | #ifdef SINGLE_PRECISION 44 | # define FLT(x) x ## f /* floating point literal constant */ 45 | # define REAL float 46 | # define ABS(x) fabsf(x) 47 | # define SQRT(x) sqrtf(x) 48 | # define HYPOT(x) hypotf(x) 49 | # define LOG(x) logf(x) 50 | # define EXP(x) expf(x) 51 | # define SIN(x) sinf(x) 52 | # define COS(x) cosf(x) 53 | # define TAN(x) tanf(x) 54 | # define ASIN(x) asinf(x) 55 | # define ACOS(x) acosf(x) 56 | # define ATAN(x) atanf(x) 57 | #else 58 | # define FLT(x) x /* floating point literal constant */ 59 | # define REAL double 60 | # define ABS(x) fabs(x) 61 | # define SQRT(x) sqrt(x) 62 | # define HYPOT(x) hypot(x) 63 | # define LOG(x) log(x) 64 | # define EXP(x) exp(x) 65 | # define SIN(x) sin(x) 66 | # define COS(x) cos(x) 67 | # define TAN(x) tan(x) 68 | # define ASIN(x) asin(x) 69 | # define ACOS(x) acos(x) 70 | # define ATAN(x) atan(x) 71 | #endif 72 | 73 | 74 | /* Helper macro for simple FORTRAN-like loops. */ 75 | #define LOOP(var,num) for (var = 1; var <= num; ++var) 76 | 77 | #define MAX(a, b) ((a) >= (b) ? (a) : (b)) 78 | #define MIN(a, b) ((a) <= (b) ? (a) : (b)) 79 | 80 | /* Macro `HOW_MANY(a,b)` yields the minimal number of chunks with `b` elements 81 | needed to store `a` elements. Both `a` and `b` must be integers. */ 82 | #define HOW_MANY(a,b) ((((b) - 1) + (a))/(b)) 83 | 84 | /* Macro `ROUND_UP(a,b)` yields the integer `a` rounded up to a multiple of 85 | integer `b`. */ 86 | #define ROUND_UP(a,b) (HOW_MANY(a,b)*(b)) 87 | 88 | /* Macro `ADDRESS(type,base,offset)` yields a `type*` address at `offset` (in 89 | bytes) from `base` address. */ 90 | #define ADDRESS(type, base, offset) ((type*)((char*)(base) + (offset))) 91 | 92 | /* Macro `OFFSET(type, field)` yields the offset (in bytes) of member `field` 93 | in structure/class `type`. */ 94 | #ifdef offsetof 95 | # define OFFSET(type, field) offsetof(type, field) 96 | #else 97 | # define OFFSET(type, field) ((char*)&((type*)0)->field - (char*)0) 98 | #endif 99 | 100 | /*---------------------------------------------------------------------------*/ 101 | /* DECLARATIONS OF PRIVATE FUNCTIONS */ 102 | 103 | static int 104 | cobylb(const INTEGER n, const INTEGER m, 105 | cobyla_calcfc* calcfc, void* calcfc_data, REAL x[], 106 | const REAL rhobeg, const REAL rhoend, const INTEGER iprint, 107 | INTEGER* maxfun, REAL con[], REAL sim[], REAL simi[], 108 | REAL datmat[], REAL a[], REAL vsig[], REAL veta[], 109 | REAL sigbar[], REAL dx[], REAL w[], INTEGER iact[]); 110 | 111 | static void 112 | trstlp(const INTEGER n, const INTEGER m, const REAL a[], const REAL b[], 113 | const REAL rho, REAL dx[], INTEGER* ifull, INTEGER iact[], REAL z[], 114 | REAL zdota[], REAL vmultc[], REAL sdirn[], REAL dxnew[], REAL vmultd[]); 115 | 116 | static void 117 | print_calcfc(FILE* output, INTEGER n, INTEGER nfvals, 118 | REAL f, REAL maxcv, const REAL x[]); 119 | 120 | 121 | int 122 | raw_cobyla(INTEGER n, INTEGER m, cobyla_calcfc* calcfc, void* calcfc_data, 123 | REAL x[], REAL rhobeg, REAL rhoend, INTEGER iprint, 124 | INTEGER* maxfun, REAL w[], INTEGER iact[]) 125 | { 126 | /* Partition the working space array W to provide the storage that is needed 127 | for the main calculation. */ 128 | INTEGER mpp = m + 2; 129 | REAL* con = w; 130 | REAL* sim = con + mpp; 131 | REAL* simi = sim + n*n + n; 132 | REAL* datmat = simi + n*n; 133 | REAL* a = datmat + n*mpp + mpp; 134 | REAL* vsig = a + m*n + n; 135 | REAL* veta = vsig + n; 136 | REAL* sigbar = veta + n; 137 | REAL* dx = sigbar + n; 138 | REAL* work = dx + n; 139 | return cobylb(n, m, calcfc, calcfc_data, x, rhobeg, rhoend, iprint, maxfun, 140 | con, sim, simi, datmat, a, vsig, veta, sigbar, dx, work, iact); 141 | } 142 | 143 | /*---------------------------------------------------------------------------*/ 144 | /* FORTRAN support. */ 145 | 146 | #ifdef FORTRAN_NAME 147 | 148 | /* CALCFC_WRAPPER is a wrapper function, it assumes a CALCFC subroutine written 149 | in FORTRAN. */ 150 | static REAL 151 | calcfc_wrapper(INTEGER n, INTEGER m, const REAL x[], REAL con[], void* data) 152 | { 153 | # define fc FORTRAN_NAME(calcfc,CALCFC) 154 | REAL f; 155 | extern void fc(INTEGER* n, INTEGER* m, const REAL x[], REAL* f, REAL con[]); 156 | fc(&n, &m, x, &f, con); 157 | return f; 158 | # undef fc 159 | } 160 | 161 | int 162 | FORTRAN_NAME(cobyla,COBYLA)(INTEGER* n, INTEGER* m, REAL x[], REAL* rhobeg, 163 | REAL* rhoend, INTEGER* iprint, INTEGER* maxfun, 164 | REAL w[], INTEGER iact[]) 165 | { 166 | (void)cobyla(*n, *m, calcfc_wrapper, NULL, x, *rhobeg, *rhoend, 167 | *iprint, maxfun, w, iact); 168 | return 0; 169 | } 170 | 171 | #endif /* FORTRAN_NAME */ 172 | 173 | /*---------------------------------------------------------------------------*/ 174 | /* Reverse communication version. */ 175 | 176 | struct _cobyla_context { 177 | INTEGER n; /* number of variables */ 178 | INTEGER m; /* number of constraints */ 179 | INTEGER iprint; 180 | INTEGER maxfun; 181 | INTEGER nfvals; 182 | REAL rhobeg; 183 | REAL rhoend; 184 | 185 | /* Workspace addresses. */ 186 | INTEGER* iact; 187 | REAL* con; 188 | REAL* sim; 189 | REAL* simi; 190 | REAL* datmat; 191 | REAL* a; 192 | REAL* vsig; 193 | REAL* veta; 194 | REAL* sigbar; 195 | REAL* dx; 196 | REAL* w; 197 | 198 | REAL parmu, parsig, prerec, prerem, rho, f; 199 | INTEGER ibrnch, iflag, ifull, jdrop; 200 | 201 | int status; 202 | }; 203 | 204 | cobyla_context_t* 205 | cobyla_create(INTEGER n, INTEGER m, REAL rhobeg, REAL rhoend, 206 | INTEGER iprint, INTEGER maxfun) 207 | { 208 | cobyla_context_t* ctx; 209 | long size, offset1, offset2; 210 | INTEGER mpp; 211 | 212 | /* Check arguments. */ 213 | if (n < 1 || m < 0 || rhobeg < rhoend || rhoend <= 0 || maxfun < 1) { 214 | errno = EINVAL; 215 | return NULL; 216 | } 217 | 218 | /* Allocate memory. */ 219 | size = sizeof(cobyla_context_t); 220 | offset1 = ROUND_UP(size, sizeof(INTEGER)); 221 | size = offset1 + (m + 1)*sizeof(INTEGER); 222 | offset2 = ROUND_UP(size, sizeof(REAL)); 223 | size = offset2 + (n*(3*n + 2*m + 11) + 4*m + 6)*sizeof(REAL); 224 | ctx = (cobyla_context_t*)malloc(size); 225 | if (ctx == NULL) { 226 | return NULL; 227 | } 228 | memset(ctx, 0, size); 229 | ctx->n = n; 230 | ctx->m = m; 231 | ctx->nfvals = 0; /* indicate a fresh start */ 232 | ctx->status = COBYLA_ITERATE; 233 | ctx->iprint = iprint; 234 | ctx->maxfun = maxfun; 235 | ctx->rhobeg = rhobeg; 236 | ctx->rhoend = rhoend; 237 | 238 | /* Partition the working space array W to provide the storage that is needed 239 | for the main calculation. */ 240 | mpp = m + 2; 241 | ctx->iact = ADDRESS(INTEGER, ctx, offset1); 242 | ctx->con = ADDRESS(REAL, ctx, offset2); 243 | ctx->sim = ctx->con + mpp; 244 | ctx->simi = ctx->sim + n*n + n; 245 | ctx->datmat = ctx->simi + n*n; 246 | ctx->a = ctx->datmat + n*mpp + mpp; 247 | ctx->vsig = ctx->a + m*n + n; 248 | ctx->veta = ctx->vsig + n; 249 | ctx->sigbar = ctx->veta + n; 250 | ctx->dx = ctx->sigbar + n; 251 | ctx->w = ctx->dx + n; 252 | 253 | return ctx; 254 | } 255 | 256 | void 257 | cobyla_delete(cobyla_context_t* ctx) 258 | { 259 | if (ctx != NULL) { 260 | free((void*)ctx); 261 | } 262 | } 263 | 264 | int 265 | cobyla_restart(cobyla_context_t* ctx) 266 | { 267 | if (ctx == NULL) { 268 | errno = EFAULT; 269 | return COBYLA_BAD_ADDRESS; 270 | } 271 | ctx->nfvals = 0; 272 | ctx->status = COBYLA_ITERATE; 273 | return ctx->status; 274 | } 275 | 276 | int 277 | cobyla_get_status(const cobyla_context_t* ctx) 278 | { 279 | if (ctx == NULL) { 280 | errno = EFAULT; 281 | return COBYLA_BAD_ADDRESS; 282 | } 283 | return ctx->status; 284 | } 285 | 286 | INTEGER 287 | cobyla_get_nevals(const cobyla_context_t* ctx) 288 | { 289 | if (ctx == NULL) { 290 | errno = EFAULT; 291 | return -1; 292 | } 293 | return ctx->nfvals; 294 | } 295 | 296 | REAL 297 | cobyla_get_rho(const cobyla_context_t* ctx) 298 | { 299 | if (ctx == NULL) { 300 | errno = EFAULT; 301 | return -1; 302 | } 303 | return ctx->rho; 304 | } 305 | 306 | REAL 307 | cobyla_get_last_f(const cobyla_context_t* ctx) 308 | { 309 | if (ctx == NULL) { 310 | errno = EFAULT; 311 | return -1; 312 | } 313 | return ctx->f; 314 | } 315 | 316 | /* Include this file with the macro _COBYLA_REVCOM defined to 317 | generate the code `newuoa_iterate` in place of `newuob`. */ 318 | #define _COBYLA_REVCOM 1 319 | #include __FILE__ 320 | #undef _COBYLA_REVCOM 321 | 322 | #endif /* _COBYLA_PART1 */ 323 | 324 | /* Define macros mimicking FORTRAN indexing. */ 325 | #define A(a1,a2) a[a1 - 1 + n*(a2 - 1)] 326 | #define CON(a1) con[a1 - 1] 327 | #define DATMAT(a1,a2) datmat[a1 - 1 + mpp*(a2 - 1)] 328 | #define DX(a1) dx[a1 - 1] 329 | #define IACT(a1) iact[a1 - 1] 330 | #define SIGBAR(a1) sigbar[a1 - 1] 331 | #define SIM(a1,a2) sim[a1 - 1 + n*(a2 - 1)] 332 | #define SIMI(a1,a2) simi[a1 - 1 + n*(a2 - 1)] 333 | #define VETA(a1) veta[a1 - 1] 334 | #define VSIG(a1) vsig[a1 - 1] 335 | #define W(a1) w[a1 - 1] 336 | #define X(a1) x[a1 - 1] 337 | 338 | #ifdef _COBYLA_REVCOM 339 | # define RESTORE(var) var = ctx->var 340 | # define SAVE(var) ctx->var = var 341 | #endif 342 | 343 | #ifdef _COBYLA_REVCOM 344 | int 345 | cobyla_iterate(cobyla_context_t* ctx, REAL f, REAL x[], REAL c[]) 346 | #else 347 | static int 348 | cobylb(const INTEGER n, const INTEGER m, 349 | cobyla_calcfc* calcfc, void* calcfc_data, REAL x[], 350 | const REAL rhobeg, const REAL rhoend, const INTEGER iprint, 351 | INTEGER* _maxfun, REAL con[], REAL sim[], REAL simi[], 352 | REAL datmat[], REAL a[], REAL vsig[], REAL veta[], 353 | REAL sigbar[], REAL dx[], REAL w[], INTEGER iact[]) 354 | #endif 355 | { 356 | /* Constants. */ 357 | const REAL zero = FLT(0.0); 358 | const REAL one = FLT(1.0); 359 | const REAL alpha = FLT(0.25); 360 | const REAL beta = FLT(2.1); 361 | const REAL gamma = FLT(0.5); 362 | const REAL delta = FLT(1.1); 363 | 364 | /* Local variables (for each type, real or integer, the first group of 365 | variables are those which must be preserved between calls in a reverse 366 | communication version of the algorithm). */ 367 | REAL parmu, parsig, prerec, prerem, rho; 368 | REAL barmu, cvmaxm, cvmaxp, dxsign, edgmax, error, pareta, phi, phimin, 369 | ratio, resmax, resnew, sum, temp, tempa, trured, vmnew, vmold; 370 | INTEGER ibrnch, iflag, ifull, jdrop, nfvals, maxfun; 371 | INTEGER i, j, k, l, mp, mpp, np, nbest; 372 | #ifdef _COBYLA_REVCOM 373 | INTEGER n, m, iprint; 374 | REAL rhobeg, rhoend; 375 | REAL *con, *sim, *simi, *datmat, *a, *vsig, *veta, *sigbar, *dx, *w; 376 | INTEGER *iact; 377 | #else 378 | REAL f; 379 | #endif 380 | int status; 381 | 382 | #ifdef _COBYLA_REVCOM 383 | /* Minimal checking and restore initial set of variables. */ 384 | if (ctx == NULL) { 385 | errno = EFAULT; 386 | return COBYLA_BAD_ADDRESS; 387 | } 388 | RESTORE(n); 389 | RESTORE(m); 390 | RESTORE(iprint); 391 | RESTORE(maxfun); 392 | RESTORE(nfvals); 393 | RESTORE(rhobeg); 394 | RESTORE(rhoend); 395 | RESTORE(iact); 396 | RESTORE(con); 397 | RESTORE(sim); 398 | RESTORE(simi); 399 | RESTORE(datmat); 400 | RESTORE(a); 401 | RESTORE(vsig); 402 | RESTORE(veta); 403 | RESTORE(sigbar); 404 | RESTORE(dx); 405 | RESTORE(w); 406 | RESTORE(status); 407 | if (x == NULL || (c == NULL && m > 0)) { 408 | errno = EFAULT; 409 | ctx->status = COBYLA_BAD_ADDRESS; 410 | return COBYLA_BAD_ADDRESS; 411 | } 412 | if (status != COBYLA_ITERATE || nfvals < 0) { 413 | errno = EINVAL; 414 | ctx->status = COBYLA_CORRUPTED; 415 | return ctx->status; 416 | } 417 | #endif 418 | 419 | /* Set the initial values of some parameters. The last column of SIM holds 420 | the optimal vertex of the current simplex, and the preceding N columns 421 | hold the displacements from the optimal vertex to the other vertices. 422 | Further, SIMI holds the inverse of the matrix that is contained in the 423 | first N columns of SIM. */ 424 | np = n + 1; 425 | mp = m + 1; 426 | mpp = m + 2; 427 | #ifdef _COBYLA_REVCOM 428 | if (nfvals == 0) { 429 | /* This is the first function evaluation. Proceed with initialization. */ 430 | status = COBYLA_INITIAL_ITERATE; 431 | prerec = zero; /* avoids warnings */ 432 | prerem = zero; /* avoids warnings */ 433 | parsig = zero; /* avoids warnings */ 434 | iflag = 0; /* avoids warnings */ 435 | #else 436 | maxfun = *_maxfun; 437 | nfvals = 0; 438 | #endif 439 | rho = rhobeg; 440 | parmu = zero; 441 | jdrop = np; 442 | ibrnch = 0; 443 | temp = one/rho; 444 | LOOP(i,n) { 445 | SIM(i,np) = X(i); 446 | LOOP(j,n) { 447 | SIM(i,j) = zero; 448 | SIMI(i,j) = zero; 449 | } 450 | SIM(i,i) = rho; 451 | SIMI(i,i) = temp; 452 | } 453 | if (iprint >= 2) { 454 | fprintf(stdout, "\n The initial value of RHO is%13.6E" 455 | " and PARMU is set to zero.\n", (double)rho); 456 | } 457 | #ifdef _COBYLA_REVCOM 458 | } else { 459 | /* This is not the first function evaluation. Restore other local 460 | variables and jump to the place where function value is expected. */ 461 | RESTORE(parmu); 462 | RESTORE(parsig); 463 | RESTORE(prerec); 464 | RESTORE(prerem); 465 | RESTORE(rho); 466 | RESTORE(ibrnch); 467 | RESTORE(iflag); 468 | RESTORE(ifull); 469 | RESTORE(jdrop); 470 | goto new_eval; 471 | } 472 | #endif 473 | 474 | /* Make the next call of the user-supplied subroutine CALCFC. These 475 | instructions are also used for calling CALCFC during the iterations 476 | of the algorithm. */ 477 | call_calcfc: 478 | if (nfvals >= maxfun && nfvals > 0) { 479 | status = COBYLA_TOO_MANY_EVALUATIONS; 480 | fprintf(stderr, "Return from subroutine COBYLA because %s.\n", 481 | cobyla_reason(status)); 482 | goto L_600; 483 | } 484 | #ifdef _COBYLA_REVCOM 485 | if (status == COBYLA_INITIAL_ITERATE) { 486 | /* We already know the functiuon value. */ 487 | status = COBYLA_ITERATE; 488 | } else { 489 | /* Request a new function evaluation from the caller and branch to save 490 | local variables in the context structure. */ 491 | status = COBYLA_ITERATE; 492 | goto save; 493 | } 494 | /* We arrive here when caller has computed a new function value. */ 495 | new_eval: 496 | #else 497 | f = calcfc(n, m, x, con, calcfc_data); 498 | #endif 499 | ++nfvals; 500 | 501 | /* Estimate the worst constraint RESMAX. */ 502 | resmax = zero; 503 | #ifdef _COBYLA_REVCOM 504 | for (k = 0; k < m; ++k) { 505 | temp = c[k]; 506 | con[k] = temp; 507 | if (resmax < -temp) { 508 | resmax = -temp; 509 | } 510 | } 511 | #else 512 | for (k = 0; k < m; ++k) { 513 | if (resmax < (temp = -con[k])) { 514 | resmax = temp; 515 | } 516 | } 517 | #endif 518 | if (nfvals == iprint - 1 || iprint == 3) { 519 | print_calcfc(stdout, n, nfvals, f, resmax, &X(1)); 520 | } 521 | CON(mp) = f; 522 | CON(mpp) = resmax; 523 | if (ibrnch == 1) goto L_440; 524 | 525 | /* Set the recently calculated function values in a column of DATMAT. This 526 | array has a column for each vertex of the current simplex, the entries of 527 | each column being the values of the constraint functions (if any) followed 528 | by the objective function and the greatest constraint violation at the 529 | vertex. */ 530 | LOOP(k,mpp) { 531 | DATMAT(k,jdrop) = CON(k); 532 | } 533 | if (nfvals > np) goto L_130; 534 | 535 | /* Exchange the new vertex of the initial simplex with the optimal vertex if 536 | necessary. Then, if the initial simplex is not complete, pick its next 537 | vertex and calculate the function values there. */ 538 | if (jdrop <= n) { 539 | if (DATMAT(mp,np) <= f) { 540 | X(jdrop) = SIM(jdrop,np); 541 | } else { 542 | SIM(jdrop,np) = X(jdrop); 543 | LOOP(k,mpp) { 544 | DATMAT(k,jdrop) = DATMAT(k,np); 545 | DATMAT(k,np) = CON(k); 546 | } 547 | LOOP(k,jdrop) { 548 | temp = zero; 549 | SIM(jdrop,k) = -rho; 550 | for (i = k; i <= jdrop; ++i) { 551 | temp -= SIMI(i,k); 552 | } 553 | SIMI(jdrop,k) = temp; 554 | } 555 | } 556 | } 557 | if (nfvals <= n) { 558 | jdrop = nfvals; 559 | X(jdrop) += rho; 560 | goto call_calcfc; 561 | } 562 | L_130: 563 | ibrnch = 1; 564 | 565 | /* Identify the optimal vertex of the current simplex. */ 566 | L_140: 567 | phimin = DATMAT(mp,np) + parmu*DATMAT(mpp,np); 568 | nbest = np; 569 | LOOP(j,n) { 570 | temp = DATMAT(mp,j) + parmu*DATMAT(mpp,j); 571 | if (temp < phimin) { 572 | nbest = j; 573 | phimin = temp; 574 | } else if (temp == phimin && parmu == zero) { 575 | if (DATMAT(mpp,j) < DATMAT(mpp,nbest)) nbest = j; 576 | } 577 | } 578 | 579 | /* Switch the best vertex into pole position if it is not there already, 580 | and also update SIM, SIMI and DATMAT. */ 581 | if (nbest <= n) { 582 | LOOP(i,mpp) { 583 | temp = DATMAT(i,np); 584 | DATMAT(i,np) = DATMAT(i,nbest); 585 | DATMAT(i,nbest) = temp; 586 | } 587 | LOOP(i,n) { 588 | temp = SIM(i,nbest); 589 | SIM(i,nbest) = zero; 590 | SIM(i,np) += temp; 591 | tempa = zero; 592 | LOOP(k,n) { 593 | SIM(i,k) -= temp; 594 | tempa -= SIMI(k,i); 595 | } 596 | SIMI(nbest,i) = tempa; 597 | } 598 | } 599 | 600 | /* Make an error return if SIGI is a poor approximation to the inverse of 601 | the leading N by N submatrix of SIG. */ 602 | error = zero; 603 | LOOP(i,n) { 604 | LOOP(j,n) { 605 | temp = (i == j ? -one : zero); 606 | LOOP(k,n) { 607 | temp += SIMI(i,k)*SIM(k,j); 608 | } 609 | temp = ABS(temp); 610 | error = MAX(error, temp); 611 | } 612 | } 613 | if (error > FLT(0.1)) { 614 | status = COBYLA_ROUNDING_ERRORS; 615 | if (iprint >= 1) { 616 | fprintf(stderr, "Return from subroutine COBYLA because %s.\n", 617 | cobyla_reason(status)); 618 | } 619 | goto L_600; 620 | } 621 | 622 | /* Calculate the coefficients of the linear approximations to the objective 623 | and constraint functions, placing minus the objective function gradient 624 | after the constraint gradients in the array A. The vector W is used for 625 | working space. */ 626 | LOOP(k,mp) { 627 | CON(k) = -DATMAT(k,np); 628 | LOOP(j,n) { 629 | W(j) = DATMAT(k,j) + CON(k); 630 | } 631 | LOOP(i,n) { 632 | temp = zero; 633 | LOOP(j,n) { 634 | temp += W(j)*SIMI(j,i); 635 | } 636 | A(i,k) = (k == mp ? -temp : temp); 637 | } 638 | } 639 | 640 | /* Calculate the values of SIGMA and ETA, and set IFLAG=0 if the current 641 | simplex is not acceptable. */ 642 | iflag = 1; 643 | parsig = alpha*rho; 644 | pareta = beta*rho; 645 | LOOP(j,n) { 646 | REAL wsig = zero; 647 | REAL weta = zero; 648 | LOOP(i,n) { 649 | wsig += SIMI(j,i)*SIMI(j,i); 650 | weta += SIM(i,j)*SIM(i,j); 651 | } 652 | VSIG(j) = one/SQRT(wsig); 653 | VETA(j) = SQRT(weta); 654 | if (VSIG(j) < parsig || VETA(j) > pareta) iflag = 0; 655 | } 656 | 657 | /* If a new vertex is needed to improve acceptability, then decide which 658 | vertex to drop from the simplex. */ 659 | if (ibrnch == 1 || iflag == 1) goto L_370; 660 | jdrop = 0; 661 | temp = pareta; 662 | LOOP(j,n) { 663 | if (VETA(j) > temp) { 664 | jdrop = j; 665 | temp = VETA(j); 666 | } 667 | } 668 | if (jdrop == 0) { 669 | LOOP(j,n) { 670 | if (VSIG(j) < temp) { 671 | jdrop = j; 672 | temp = VSIG(j); 673 | } 674 | } 675 | } 676 | 677 | /* Calculate the step to the new vertex and its sign. */ 678 | temp = gamma*rho*VSIG(jdrop); 679 | LOOP(i,n) { 680 | DX(i) = temp*SIMI(jdrop,i); 681 | } 682 | cvmaxp = zero; 683 | cvmaxm = zero; 684 | sum = zero; /* FIXME: `sum` was uninitialized */ 685 | LOOP(k,mp) { 686 | sum = zero; 687 | LOOP(i,n) { 688 | sum = sum + A(i,k)*DX(i); 689 | } 690 | if (k < mp) { 691 | temp = DATMAT(k,np); 692 | cvmaxp = MAX(cvmaxp, -sum - temp); 693 | cvmaxm = MAX(cvmaxm, sum - temp); 694 | } 695 | } 696 | if (parmu*(cvmaxp - cvmaxm) > sum + sum) { 697 | dxsign = -one; 698 | } else { 699 | dxsign = one; 700 | } 701 | 702 | /* Update the elements of SIM and SIMI, and set the next X. */ 703 | temp = zero; 704 | LOOP(i,n) { 705 | DX(i) *= dxsign; 706 | SIM(i,jdrop) = DX(i); 707 | temp += SIMI(jdrop,i)*DX(i); 708 | } 709 | LOOP(i,n) { 710 | SIMI(jdrop,i) /= temp; 711 | } 712 | LOOP(j,n) { 713 | if (j != jdrop) { 714 | temp = zero; 715 | LOOP(i,n) { 716 | temp += SIMI(j,i)*DX(i); 717 | } 718 | LOOP(i,n) { 719 | SIMI(j,i) -= temp*SIMI(jdrop,i); 720 | } 721 | } 722 | X(j) = SIM(j,np) + DX(j); 723 | } 724 | goto call_calcfc; 725 | 726 | /* Calculate DX = X(*) - X(0). Branch if the length of DX is less than 727 | 0.5*RHO. */ 728 | L_370: 729 | { 730 | REAL* z = w; 731 | REAL* zdota = z + n*n; 732 | REAL* vmc = zdota + n; 733 | REAL* sdirn = vmc + mp; 734 | REAL* dxnew = sdirn + n; 735 | REAL* vmd = dxnew + n; 736 | trstlp(n, m, a, con, rho, dx, &ifull, iact, z, zdota, 737 | vmc, sdirn, dxnew, vmd); 738 | } 739 | if (ifull == 0) { 740 | temp = zero; 741 | LOOP(i,n) { 742 | temp += DX(i)*DX(i); 743 | } 744 | if (temp < FLT(0.25)*rho*rho) { 745 | ibrnch = 1; 746 | goto L_550; 747 | } 748 | } 749 | 750 | /* Predict the change to F and the new maximum constraint violation if the 751 | variables are altered from X(0) to X(0)+DX. */ 752 | resnew = zero; 753 | CON(mp) = zero; 754 | sum = zero; /* FIXME: `sum` was uninitialized */ 755 | LOOP(k,mp) { 756 | sum = CON(k); 757 | LOOP(i,n) { 758 | sum -= A(i,k)*DX(i); 759 | } 760 | if (k < mp) resnew = MAX(resnew, sum); 761 | } 762 | 763 | /* Increase PARMU if necessary and branch back if this change alters the 764 | optimal vertex. Otherwise PREREM and PREREC will be set to the predicted 765 | reductions in the merit function and the maximum constraint violation 766 | respectively. */ 767 | prerec = DATMAT(mpp,np) - resnew; 768 | barmu = (prerec > zero ? sum/prerec : zero); 769 | if (parmu < FLT(1.5)*barmu) { 770 | parmu = FLT(2.0)*barmu; 771 | if (iprint >= 2) { 772 | fprintf(stdout, "\n Increase in PARMU to%13.6E\n", (double)parmu); 773 | } 774 | phi = DATMAT(mp,np) + parmu*DATMAT(mpp,np); 775 | LOOP(j,n) { 776 | temp = DATMAT(mp,j) + parmu*DATMAT(mpp,j); 777 | if (temp < phi) goto L_140; 778 | if (temp == phi && parmu == zero) { 779 | if (DATMAT(mpp,j) < DATMAT(mpp,np)) goto L_140; 780 | } 781 | } 782 | } 783 | prerem = parmu*prerec - sum; 784 | 785 | /* Calculate the constraint and objective functions at X(*). Then find the 786 | actual reduction in the merit function. */ 787 | LOOP(i,n) { 788 | X(i) = SIM(i,np) + DX(i); 789 | } 790 | ibrnch = 1; 791 | goto call_calcfc; 792 | L_440: 793 | vmold = DATMAT(mp,np) + parmu*DATMAT(mpp,np); 794 | vmnew = f + parmu*resmax; 795 | trured = vmold - vmnew; 796 | if (parmu == zero && f == DATMAT(mp,np)) { 797 | prerem = prerec; 798 | trured = DATMAT(mpp,np) - resmax; 799 | } 800 | 801 | /* Begin the operations that decide whether X(*) should replace one of the 802 | vertices of the current simplex, the change being mandatory if TRURED is 803 | positive. Firstly, JDROP is set to the index of the vertex that is to be 804 | replaced. */ 805 | ratio = (trured <= zero ? one : zero); 806 | jdrop = 0; 807 | LOOP(j,n) { 808 | temp = zero; 809 | LOOP(i,n) { 810 | temp += SIMI(j,i)*DX(i); 811 | } 812 | temp = ABS(temp); 813 | if (temp > ratio) { 814 | jdrop = j; 815 | ratio = temp; 816 | } 817 | SIGBAR(j) = temp*VSIG(j); 818 | } 819 | 820 | /* Calculate the value of ell. */ 821 | edgmax = delta*rho; 822 | l = 0; 823 | LOOP(j,n) { 824 | if (SIGBAR(j) >= parsig || SIGBAR(j) >= VSIG(j)) { 825 | temp = VETA(j); 826 | if (trured > zero) { 827 | temp = zero; 828 | LOOP(i,n) { 829 | REAL tempb = DX(i) - SIM(i,j); 830 | temp += tempb*tempb; 831 | } 832 | temp = SQRT(temp); 833 | } 834 | if (temp > edgmax) { 835 | l = j; 836 | edgmax = temp; 837 | } 838 | } 839 | } 840 | if (l > 0) jdrop = l; 841 | if (jdrop == 0) goto L_550; 842 | 843 | /* Revise the simplex by updating the elements of SIM, SIMI and DATMAT. */ 844 | temp = zero; 845 | LOOP(i,n) { 846 | SIM(i,jdrop) = DX(i); 847 | temp += SIMI(jdrop,i)*DX(i); 848 | } 849 | LOOP(i,n) { 850 | SIMI(jdrop,i) = SIMI(jdrop,i)/temp; 851 | } 852 | LOOP(j,n) { 853 | if (j != jdrop) { 854 | temp = zero; 855 | LOOP(i,n) { 856 | temp += SIMI(j,i)*DX(i); 857 | } 858 | LOOP(i,n) { 859 | SIMI(j,i) -= temp*SIMI(jdrop,i); 860 | } 861 | } 862 | } 863 | LOOP(k,mpp) { 864 | DATMAT(k,jdrop) = CON(k); 865 | } 866 | 867 | /* Branch back for further iterations with the current RHO. */ 868 | if (trured > zero && trured >= FLT(0.1)*prerem) goto L_140; 869 | L_550: 870 | if (iflag == 0) { 871 | ibrnch = 0; 872 | goto L_140; 873 | } 874 | 875 | /* Otherwise reduce RHO if it is not at its least value and reset PARMU. */ 876 | if (rho > rhoend) { 877 | rho = FLT(0.5)*rho; 878 | if (rho <= FLT(1.5)*rhoend) rho = rhoend; 879 | if (parmu > zero) { 880 | REAL cmin, cmax, denom; 881 | denom = zero; 882 | LOOP(k,mp) { 883 | cmax = cmin = DATMAT(k,np); 884 | LOOP(i,n) { 885 | temp = DATMAT(k,i); 886 | cmin = MIN(cmin, temp); 887 | cmax = MAX(cmax, temp); 888 | } 889 | if (k <= m && cmin < FLT(0.5)*cmax) { 890 | temp = MAX(cmax, zero) - cmin; 891 | if (denom <= zero) { 892 | denom = temp; 893 | } else { 894 | denom = MIN(denom, temp); 895 | } 896 | } 897 | } 898 | if (denom == zero) { 899 | parmu = zero; 900 | } else if (cmax - cmin < parmu*denom) { 901 | parmu = (cmax - cmin)/denom; 902 | } 903 | } 904 | if (iprint >= 2) { 905 | fprintf(stdout, "\n Reduction in RHO to%13.6E and PARMU =%13.6E\n", 906 | (double)rho, (double)parmu); 907 | if (iprint == 2) { 908 | print_calcfc(stdout, n, nfvals, DATMAT(mp,np), DATMAT(mpp,np), 909 | &SIM(1,np)); 910 | } 911 | } 912 | goto L_140; 913 | } 914 | 915 | /* Return the best calculated values of the variables. */ 916 | if (iprint >= 1) { 917 | fprintf(stdout, "\n Normal return from subroutine COBYLA\n"); 918 | } 919 | status = COBYLA_SUCCESS; 920 | if (ifull == 1) goto L_620; 921 | L_600: 922 | LOOP(i,n) { 923 | X(i) = SIM(i,np); 924 | } 925 | f = DATMAT(mp,np); 926 | resmax = DATMAT(mpp,np); 927 | L_620: 928 | if (iprint >= 1) { 929 | print_calcfc(stdout, n, nfvals, f, resmax, &X(1)); 930 | } 931 | 932 | #ifdef _COBYLA_REVCOM 933 | /* Save local variables and return status. */ 934 | save: 935 | SAVE(nfvals); 936 | SAVE(parmu); 937 | SAVE(parsig); 938 | SAVE(prerec); 939 | SAVE(prerem); 940 | SAVE(rho); 941 | SAVE(f); 942 | SAVE(ibrnch); 943 | SAVE(iflag); 944 | SAVE(ifull); 945 | SAVE(jdrop); 946 | SAVE(status); 947 | #else 948 | /* Save number of function evaluations and return status. */ 949 | *_maxfun = nfvals; 950 | #endif 951 | return status; 952 | } 953 | 954 | /* Undefine macros mimicking FORTRAN indexing. */ 955 | #undef A 956 | #undef CON 957 | #undef DATMAT 958 | #undef DX 959 | #undef IACT 960 | #undef SIGBAR 961 | #undef SIM 962 | #undef SIMI 963 | #undef VETA 964 | #undef VSIG 965 | #undef W 966 | #undef X 967 | 968 | #ifdef _COBYLA_REVCOM 969 | # undef RESTORE 970 | # undef SAVE 971 | #endif 972 | 973 | #ifndef _COBYLA_PART2 974 | #define _COBYLA_PART2 1 975 | 976 | /* 977 | * This subroutine calculates an N-component vector DX by applying the 978 | * following two stages. In the first stage, DX is set to the shortest vector 979 | * that minimizes the greatest violation of the constraints: 980 | * 981 | * A(1,K)*DX(1)+A(2,K)*DX(2)+...+A(N,K)*DX(N) >= B(K), K=2,3,...,M, 982 | * 983 | * subject to the Euclidean length of DX being at most RHO. If its length is 984 | * strictly less than RHO, then we use the resultant freedom in DX to minimize 985 | * the objective function: 986 | * 987 | * -A(1,M+1)*DX(1)-A(2,M+1)*DX(2)-...-A(N,M+1)*DX(N) 988 | * 989 | * subject to no increase in any greatest constraint violation. This notation 990 | * allows the gradient of the objective function to be regarded as the gradient 991 | * of a constraint. Therefore the two stages are distinguished by MCON = M and 992 | * MCON > M respectively. It is possible that a degeneracy may prevent DX from 993 | * attaining the target length RHO. Then the value IFULL=0 would be set, but 994 | * usually IFULL=1 on return. 995 | * 996 | * In general NACT is the number of constraints in the active set and 997 | * IACT(1),...,IACT(NACT) are their indices, while the remainder of IACT 998 | * contains a permutation of the remaining constraint indices. Further, Z is 999 | * an orthogonal matrix whose first NACT columns can be regarded as the result 1000 | * of Gram-Schmidt applied to the active constraint gradients. For 1001 | * J=1,2,...,NACT, the number ZDOTA(J) is the scalar product of the J-th column 1002 | * of Z with the gradient of the J-th active constraint. DX is the current 1003 | * vector of variables and here the residuals of the active constraints should 1004 | * be zero. Further, the active constraints have nonnegative Lagrange 1005 | * multipliers that are held at the beginning of VMULTC. The remainder of this 1006 | * vector holds the residuals of the inactive constraints at DX, the ordering 1007 | * of the components of VMULTC being in agreement with the permutation of the 1008 | * indices of the constraints that is in IACT. All these residuals are 1009 | * nonnegative, which is achieved by the shift RESMAX that makes the least 1010 | * residual zero. 1011 | * 1012 | * Initialize Z and some other variables. The value of RESMAX will be 1013 | * appropriate to DX=0, while ICON will be the index of a most violated 1014 | * constraint if RESMAX is positive. Usually during the first stage the vector 1015 | * SDIRN gives a search direction that reduces all the active constraint 1016 | * violations by one simultaneously. 1017 | */ 1018 | 1019 | /* Define macros mimicking FORTRAN indexing. */ 1020 | #define A(a1,a2) a[a1 - 1 + n*(a2 - 1)] 1021 | #define B(a1) b[a1 - 1] 1022 | #define DX(a1) dx[a1 - 1] 1023 | #define DXNEW(a1) dxnew[a1 - 1] 1024 | #define IACT(a1) iact[a1 - 1] 1025 | #define SDIRN(a1) sdirn[a1 - 1] 1026 | #define VMULTC(a1) vmultc[a1 - 1] 1027 | #define VMULTD(a1) vmultd[a1 - 1] 1028 | #define Z(a1,a2) z[a1 - 1 + n*(a2 - 1)] 1029 | #define ZDOTA(a1) zdota[a1 - 1] 1030 | 1031 | static void 1032 | trstlp(const INTEGER n, const INTEGER m, const REAL a[], const REAL b[], 1033 | const REAL rho, REAL dx[], INTEGER* ifull, INTEGER iact[], REAL z[], 1034 | REAL zdota[], REAL vmultc[], REAL sdirn[], REAL dxnew[], REAL vmultd[]) 1035 | { 1036 | /* Constants. */ 1037 | const REAL zero = FLT(0.0); 1038 | const REAL one = FLT(1.0); 1039 | const REAL tiny = FLT(1.0e-6); 1040 | const REAL Op1 = FLT(0.1); 1041 | const REAL Op2 = FLT(0.2); 1042 | 1043 | /* Local variables (FIXME: `iout` was unused). */ 1044 | REAL acca, accb, alpha, beta, dd, optnew, optold, ratio, resmax, resold, sd, 1045 | sp, spabs, ss, step, stpful, sum, sumabs, temp, tempa, tempb, tot, vsave, 1046 | zdotv, zdotw, zdvabs, zdwabs; 1047 | INTEGER i, icon, icount, isave, j, k, kk, kl, kp, kw, mcon, nact, nactx; 1048 | 1049 | *ifull = 1; 1050 | icon = 0; /* FIXME: `icon` was uninitialized */ 1051 | mcon = m; 1052 | nact = 0; 1053 | resmax = zero; 1054 | resold = zero; /* FIXME: `resold` was uninitialized */ 1055 | LOOP(i,n) { 1056 | LOOP(j,n) { 1057 | Z(i,j) = zero; 1058 | } 1059 | Z(i,i) = one; 1060 | DX(i) = zero; 1061 | } 1062 | if (m >= 1) { 1063 | LOOP(k,m) { 1064 | if (B(k) > resmax) { 1065 | resmax = B(k); 1066 | icon = k; 1067 | } 1068 | } 1069 | LOOP(k,m) { 1070 | IACT(k) = k; 1071 | VMULTC(k) = resmax - B(k); 1072 | } 1073 | } 1074 | if (resmax == zero) goto L_480; 1075 | LOOP(i,n) { 1076 | SDIRN(i) = zero; 1077 | } 1078 | 1079 | /* End the current stage of the calculation if 3 consecutive iterations have 1080 | either failed to reduce the best calculated value of the objective 1081 | function or to increase the number of active constraints since the best 1082 | value was calculated. This strategy prevents cycling, but there is a 1083 | remote possibility that it will cause premature termination. */ 1084 | L_60: 1085 | optold = zero; 1086 | icount = 0; 1087 | L_70: 1088 | if (mcon == m) { 1089 | optnew = resmax; 1090 | } else { 1091 | optnew = zero; 1092 | LOOP(i,n) { 1093 | optnew -= DX(i)*A(i,mcon); 1094 | } 1095 | } 1096 | if (icount == 0 || optnew < optold) { 1097 | optold = optnew; 1098 | nactx = nact; 1099 | icount = 3; 1100 | } else if (nact > nactx) { 1101 | nactx = nact; 1102 | icount = 3; 1103 | } else { 1104 | --icount; 1105 | if (icount == 0) goto L_490; 1106 | } 1107 | 1108 | /* If ICON exceeds NACT, then we add the constraint with index IACT(ICON) to 1109 | the active set. Apply Givens rotations so that the last N-NACT-1 columns 1110 | of Z are orthogonal to the gradient of the new constraint, a scalar 1111 | product being set to zero if its nonzero value could be due to computer 1112 | rounding errors. The array DXNEW is used for working space. */ 1113 | if (icon <= nact) goto L_260; 1114 | kk = IACT(icon); 1115 | LOOP(i,n) { 1116 | DXNEW(i) = A(i,kk); 1117 | } 1118 | tot = zero; 1119 | for (k = n; k > nact; --k) { 1120 | sp = zero; 1121 | spabs = zero; 1122 | LOOP(i,n) { 1123 | temp = Z(i,k)*DXNEW(i); 1124 | sp += temp; 1125 | spabs += ABS(temp); 1126 | } 1127 | acca = spabs + Op1*ABS(sp); 1128 | accb = spabs + Op2*ABS(sp); 1129 | if (spabs >= acca || acca >= accb) sp = zero; 1130 | if (tot == zero) { 1131 | tot = sp; 1132 | } else { 1133 | kp = k + 1; 1134 | temp = SQRT(sp*sp + tot*tot); 1135 | alpha = sp/temp; 1136 | beta = tot/temp; 1137 | tot = temp; 1138 | LOOP(i,n) { 1139 | temp = alpha*Z(i,k) + beta*Z(i,kp); 1140 | Z(i,kp) = alpha*Z(i,kp) - beta*Z(i,k); 1141 | Z(i,k) = temp; 1142 | } 1143 | } 1144 | } 1145 | 1146 | /* Add the new constraint if this can be done without a deletion from the 1147 | active set. */ 1148 | if (tot != zero) { 1149 | ++nact; 1150 | ZDOTA(nact) = tot; 1151 | VMULTC(icon) = VMULTC(nact); 1152 | VMULTC(nact) = zero; 1153 | goto L_210; 1154 | } 1155 | 1156 | /* The next instruction is reached if a deletion has to be made from the 1157 | active set in order to make room for the new active constraint, because 1158 | the new constraint gradient is a linear combination of the gradients of 1159 | the old active constraints. Set the elements of VMULTD to the multipliers 1160 | of the linear combination. Further, set IOUT to the index of the 1161 | constraint to be deleted, but branch if no suitable index can be found. */ 1162 | ratio = -one; 1163 | k = nact; 1164 | L_130: 1165 | zdotv = zero; 1166 | zdvabs = zero; 1167 | LOOP(i,n) { 1168 | temp = Z(i,k)*DXNEW(i); 1169 | zdotv += temp; 1170 | zdvabs += ABS(temp); 1171 | } 1172 | acca = zdvabs + Op1*ABS(zdotv); 1173 | accb = zdvabs + Op2*ABS(zdotv); 1174 | if (zdvabs < acca && acca < accb) { 1175 | temp = zdotv/ZDOTA(k); 1176 | if (temp > zero && IACT(k) <= m) { 1177 | tempa = VMULTC(k)/temp; 1178 | if (ratio < zero || tempa < ratio) { 1179 | ratio = tempa; 1180 | /* iout = k; (FIXME: `iout` unused) */ 1181 | } 1182 | } 1183 | if (k >= 2) { 1184 | kw = IACT(k); 1185 | LOOP(i,n) { 1186 | DXNEW(i) -= temp*A(i,kw); 1187 | } 1188 | } 1189 | VMULTD(k) = temp; 1190 | } else { 1191 | VMULTD(k) = zero; 1192 | } 1193 | --k; 1194 | if (k > 0) goto L_130; 1195 | if (ratio < zero) goto L_490; 1196 | 1197 | /* Revise the Lagrange multipliers and reorder the active constraints so that 1198 | the one to be replaced is at the end of the list. Also calculate the new 1199 | value of ZDOTA(NACT) and branch if it is not acceptable. */ 1200 | LOOP(k,nact) { 1201 | tempb = VMULTC(k) - ratio*VMULTD(k); 1202 | VMULTC(k) = MAX(zero, tempb); 1203 | } 1204 | if (icon < nact) { 1205 | isave = IACT(icon); 1206 | vsave = VMULTC(icon); 1207 | k = icon; 1208 | do { 1209 | kp = k + 1; 1210 | kw = IACT(kp); 1211 | sp = zero; 1212 | LOOP(i,n) { 1213 | sp += Z(i,k)*A(i,kw); 1214 | } 1215 | temp = SQRT(sp*sp + ZDOTA(kp)*ZDOTA(kp)); 1216 | alpha = ZDOTA(kp)/temp; 1217 | beta = sp/temp; 1218 | ZDOTA(kp) = alpha*ZDOTA(k); 1219 | ZDOTA(k) = temp; 1220 | LOOP(i,n) { 1221 | temp = alpha*Z(i,kp) + beta*Z(i,k); 1222 | Z(i,kp) = alpha*Z(i,k) - beta*Z(i,kp); 1223 | Z(i,k) = temp; 1224 | } 1225 | IACT(k) = kw; 1226 | VMULTC(k) = VMULTC(kp); 1227 | k = kp; 1228 | } while (k < nact); 1229 | IACT(k) = isave; 1230 | VMULTC(k) = vsave; 1231 | } 1232 | temp = zero; 1233 | LOOP(i,n) { 1234 | temp += Z(i,nact)*A(i,kk); 1235 | } 1236 | if (temp == zero) goto L_490; 1237 | ZDOTA(nact) = temp; 1238 | VMULTC(icon) = zero; 1239 | VMULTC(nact) = ratio; 1240 | 1241 | /* Update IACT and ensure that the objective function continues to be treated 1242 | as the last active constraint when MCON > M. */ 1243 | L_210: 1244 | IACT(icon) = IACT(nact); 1245 | IACT(nact) = kk; 1246 | if (mcon > m && kk != mcon) { 1247 | k = nact - 1; 1248 | sp = zero; 1249 | LOOP(i,n) { 1250 | sp += Z(i,k)*A(i,kk); 1251 | } 1252 | temp = SQRT(sp*sp + ZDOTA(nact)*ZDOTA(nact)); 1253 | alpha = ZDOTA(nact)/temp; 1254 | beta = sp/temp; 1255 | ZDOTA(nact) = alpha*ZDOTA(k); 1256 | ZDOTA(k) = temp; 1257 | LOOP(i,n) { 1258 | temp = alpha*Z(i,nact) + beta*Z(i,k); 1259 | Z(i,nact) = alpha*Z(i,k) - beta*Z(i,nact); 1260 | Z(i,k) = temp; 1261 | } 1262 | IACT(nact) = IACT(k); 1263 | IACT(k) = kk; 1264 | temp = VMULTC(k); 1265 | VMULTC(k) = VMULTC(nact); 1266 | VMULTC(nact) = temp; 1267 | } 1268 | 1269 | /* If stage one is in progress, then set SDIRN to the direction of the next 1270 | change to the current vector of variables. */ 1271 | if (mcon > m) goto L_320; 1272 | kk = IACT(nact); 1273 | temp = zero; 1274 | LOOP(i,n) { 1275 | temp += SDIRN(i)*A(i,kk); 1276 | } 1277 | temp = (temp - one)/ZDOTA(nact); 1278 | LOOP(i,n) { 1279 | SDIRN(i) -= temp*Z(i,nact); 1280 | } 1281 | goto L_340; 1282 | 1283 | /* Delete the constraint that has the index IACT(ICON) from the active 1284 | set. */ 1285 | L_260: 1286 | if (icon < nact) { 1287 | isave = IACT(icon); 1288 | vsave = VMULTC(icon); 1289 | k = icon; 1290 | do { 1291 | kp = k + 1; 1292 | kk = IACT(kp); 1293 | sp = zero; 1294 | LOOP(i,n) { 1295 | sp += Z(i,k)*A(i,kk); 1296 | } 1297 | temp = SQRT(sp*sp + ZDOTA(kp)*ZDOTA(kp)); 1298 | alpha = ZDOTA(kp)/temp; 1299 | beta = sp/temp; 1300 | ZDOTA(kp) = alpha*ZDOTA(k); 1301 | ZDOTA(k) = temp; 1302 | LOOP(i,n) { 1303 | temp = alpha*Z(i,kp) + beta*Z(i,k); 1304 | Z(i,kp) = alpha*Z(i,k) - beta*Z(i,kp); 1305 | Z(i,k) = temp; 1306 | } 1307 | IACT(k) = kk; 1308 | VMULTC(k) = VMULTC(kp); 1309 | k = kp; 1310 | } while (k < nact); 1311 | IACT(k) = isave; 1312 | VMULTC(k) = vsave; 1313 | } 1314 | --nact; 1315 | 1316 | /* If stage one is in progress, then set SDIRN to the direction of the next 1317 | change to the current vector of variables. */ 1318 | if (mcon > m) goto L_320; 1319 | temp = zero; 1320 | LOOP(i,n) { 1321 | temp += SDIRN(i)*Z(i,nact + 1); 1322 | } 1323 | LOOP(i,n) { 1324 | SDIRN(i) -= temp*Z(i,nact + 1); 1325 | } 1326 | goto L_340; 1327 | 1328 | /* Pick the next search direction of stage two. */ 1329 | L_320: 1330 | temp = one/ZDOTA(nact); 1331 | LOOP(i,n) { 1332 | SDIRN(i) = temp*Z(i,nact); 1333 | } 1334 | 1335 | /* Calculate the step to the boundary of the trust region or take the step 1336 | that reduces RESMAX to zero. The two statements below that include the 1337 | factor 1.0E-6 prevent some harmless underflows that occurred in a test 1338 | calculation. Further, we skip the step if it could be zero within a 1339 | reasonable tolerance for computer rounding errors. */ 1340 | L_340: 1341 | dd = rho*rho; 1342 | sd = zero; 1343 | ss = zero; 1344 | LOOP(i,n) { 1345 | if (ABS(DX(i)) >= tiny*rho) { 1346 | dd -= DX(i)*DX(i); 1347 | } 1348 | sd += SDIRN(i)*DX(i); 1349 | ss += SDIRN(i)*SDIRN(i); 1350 | } 1351 | if (dd <= zero) goto L_490; 1352 | temp = SQRT(ss*dd); 1353 | if (ABS(sd) >= tiny*temp) { 1354 | temp = SQRT(ss*dd + sd*sd); 1355 | } 1356 | stpful = dd/(temp + sd); 1357 | step = stpful; 1358 | if (mcon == m) { 1359 | acca = step + Op1*resmax; 1360 | accb = step + Op2*resmax; 1361 | if (step >= acca || acca >= accb) goto L_480; 1362 | step = MIN(step, resmax); 1363 | } 1364 | 1365 | /* Set DXNEW to the new variables if STEP is the steplength, and reduce 1366 | RESMAX to the corresponding maximum residual if stage one is being done. 1367 | Because DXNEW will be changed during the calculation of some Lagrange 1368 | multipliers, it will be restored to the following value later. */ 1369 | LOOP(i,n) { 1370 | DXNEW(i) = DX(i) + step*SDIRN(i); 1371 | } 1372 | if (mcon == m) { 1373 | resold = resmax; 1374 | resmax = zero; 1375 | LOOP(k,nact) { 1376 | kk = IACT(k); 1377 | temp = B(kk); 1378 | LOOP(i,n) { 1379 | temp -= A(i,kk)*DXNEW(i); 1380 | } 1381 | resmax = MAX(resmax, temp); 1382 | } 1383 | } 1384 | 1385 | /* Set VMULTD to the VMULTC vector that would occur if DX became DXNEW. A 1386 | device is included to force VMULTD(K) = 0 if deviations from this value 1387 | can be attributed to computer rounding errors. First calculate the new 1388 | Lagrange multipliers. */ 1389 | k = nact; 1390 | for (;;) { 1391 | zdotw = zero; 1392 | zdwabs = zero; 1393 | LOOP(i,n) { 1394 | temp = Z(i,k)*DXNEW(i); 1395 | zdotw += temp; 1396 | zdwabs += ABS(temp); 1397 | } 1398 | acca = zdwabs + Op1*ABS(zdotw); 1399 | accb = zdwabs + Op2*ABS(zdotw); 1400 | if (zdwabs >= acca || acca >= accb) zdotw = zero; 1401 | VMULTD(k) = zdotw/ZDOTA(k); 1402 | if (k < 2) break; 1403 | kk = IACT(k); 1404 | LOOP(i,n) { 1405 | DXNEW(i) -= VMULTD(k)*A(i,kk); 1406 | } 1407 | --k; 1408 | } 1409 | if (mcon > m && VMULTD(nact) < zero) VMULTD(nact) = zero; 1410 | 1411 | /* Complete VMULTC by finding the new constraint residuals. */ 1412 | LOOP(i,n) { 1413 | DXNEW(i) = DX(i) + step*SDIRN(i); 1414 | } 1415 | if (mcon > nact) { 1416 | kl = nact + 1; 1417 | for (k = kl; k <= mcon; ++k) { 1418 | kk = IACT(k); 1419 | sum = resmax - B(kk); 1420 | sumabs = resmax + ABS(B(kk)); 1421 | LOOP(i,n) { 1422 | temp = A(i,kk)*DXNEW(i); 1423 | sum += temp; 1424 | sumabs += ABS(temp); 1425 | } 1426 | acca = sumabs + Op1*ABS(sum); 1427 | accb = sumabs + Op2*ABS(sum); 1428 | if (sumabs >= acca || acca >= accb) sum = zero; 1429 | VMULTD(k) = sum; 1430 | } 1431 | } 1432 | 1433 | /* Calculate the fraction of the step from DX to DXNEW that will be taken. */ 1434 | ratio = one; 1435 | icon = 0; 1436 | LOOP(k,mcon) { 1437 | if (VMULTD(k) < zero) { 1438 | temp = VMULTC(k)/(VMULTC(k) - VMULTD(k)); 1439 | if (temp < ratio) { 1440 | ratio = temp; 1441 | icon = k; 1442 | } 1443 | } 1444 | } 1445 | 1446 | /* Update DX, VMULTC and RESMAX. */ 1447 | temp = one - ratio; 1448 | LOOP(i,n) { 1449 | DX(i) = temp*DX(i) + ratio*DXNEW(i); 1450 | } 1451 | LOOP(k,mcon) { 1452 | tempb = temp*VMULTC(k) + ratio*VMULTD(k); 1453 | VMULTC(k) = MAX(zero, tempb); 1454 | } 1455 | if (mcon == m) resmax = resold + ratio*(resmax - resold); 1456 | 1457 | /* If the full step is not acceptable then begin another iteration. 1458 | Otherwise switch to stage two or end the calculation. */ 1459 | if (icon > 0) goto L_70; 1460 | if (step == stpful) goto L_500; 1461 | L_480: 1462 | mcon = m + 1; 1463 | icon = mcon; 1464 | IACT(mcon) = mcon; 1465 | VMULTC(mcon) = zero; 1466 | goto L_60; 1467 | 1468 | /* We employ any freedom that may be available to reduce the objective 1469 | function before returning a DX whose length is less than RHO. */ 1470 | L_490: 1471 | if (mcon == m) goto L_480; 1472 | *ifull = 0; 1473 | L_500: 1474 | return; 1475 | } 1476 | 1477 | /* Undefine macros mimicking FORTRAN indexing. */ 1478 | #undef A 1479 | #undef B 1480 | #undef DX 1481 | #undef DXNEW 1482 | #undef IACT 1483 | #undef SDIRN 1484 | #undef VMULTC 1485 | #undef VMULTD 1486 | #undef Z 1487 | #undef ZDOTA 1488 | 1489 | /*---------------------------------------------------------------------------*/ 1490 | 1491 | const char* 1492 | cobyla_reason(int status) 1493 | { 1494 | switch (status) { 1495 | case COBYLA_ITERATE: 1496 | return "user requested to compute F(X) and C(X)"; 1497 | case COBYLA_SUCCESS: 1498 | return "algorithm was successful"; 1499 | case COBYLA_ROUNDING_ERRORS: 1500 | return "rounding errors are becoming damaging"; 1501 | case COBYLA_TOO_MANY_EVALUATIONS: 1502 | return "MAXFUN limit has been reached"; 1503 | case COBYLA_BAD_ADDRESS: 1504 | return "illegal NULL address"; 1505 | case COBYLA_CORRUPTED: 1506 | return "unexpected parameter or corrupted workspace"; 1507 | default: 1508 | return "unknown status"; 1509 | } 1510 | } 1511 | 1512 | static void 1513 | print_calcfc(FILE* output, INTEGER n, INTEGER nfvals, 1514 | REAL f, REAL maxcv, const REAL x[]) 1515 | { 1516 | INTEGER i; 1517 | fprintf(output, 1518 | "\n NFVALS =%5d F =%13.6E MAXCV =%13.6E" 1519 | "\n X =%13.6E", (int)nfvals, f, maxcv, x[0]); 1520 | for (i = 1; i < n; ++i) { 1521 | fprintf(output, (i%5 == 0 ? "\n%19.6E" : "%15.6E"), x[i]); 1522 | } 1523 | fprintf(output, "\n"); 1524 | } 1525 | 1526 | /*---------------------------------------------------------------------------*/ 1527 | 1528 | #if defined(TESTING_REVCOM) 1529 | # if defined(TESTING_FWRAP) 1530 | # error only one of TESTING_REVCOM or TESTING_FWRAP can be defined 1531 | # endif 1532 | # define TESTING 1533 | static void 1534 | testing_revcom(INTEGER n, INTEGER m, REAL rhobeg, REAL rhoend, 1535 | INTEGER iprint, INTEGER maxfun, REAL x[]); 1536 | #elif defined(TESTING_FWRAP) 1537 | # define TESTING 1538 | #endif 1539 | 1540 | #ifdef TESTING 1541 | 1542 | /***********************************************************/ 1543 | /* Main program of test problems in Report DAMTP 1992/NA5. */ 1544 | /***********************************************************/ 1545 | 1546 | static int nprob = 1; /* Problem number. */ 1547 | static cobyla_calcfc calcfc; 1548 | 1549 | int 1550 | main(void) 1551 | { 1552 | REAL r1, rhobeg, rhoend, temp, tempa, tempb, tempc, tempd; 1553 | REAL x[10], xopt[10]; 1554 | INTEGER i, m, n, icase, maxfun, iprint; 1555 | #ifndef TESTING_REVCOM 1556 | REAL w[3000]; 1557 | INTEGER iact[51]; 1558 | #endif 1559 | 1560 | for (nprob = 1; nprob <= 10; ++nprob) { 1561 | 1562 | # define PRT(s) fprintf(stdout, "\n " s "\n") 1563 | 1564 | switch(nprob) { 1565 | 1566 | case 1: 1567 | /* Minimization of a simple quadratic function of two variables. */ 1568 | PRT("Output from test problem 1 (Simple quadratic)"); 1569 | n = 2; 1570 | m = 0; 1571 | xopt[0] = -1.0; 1572 | xopt[1] = 0.0; 1573 | break; 1574 | 1575 | case 2: 1576 | /* Easy two dimensional minimization in unit circle. */ 1577 | PRT("Output from test problem 2 (2D unit circle calculation)"); 1578 | n = 2; 1579 | m = 1; 1580 | xopt[0] = SQRT(0.5); 1581 | xopt[1] = -xopt[0]; 1582 | break; 1583 | 1584 | case 3: 1585 | /* Easy three dimensional minimization in ellipsoid. */ 1586 | PRT("Output from test problem 3 (3D ellipsoid calculation)"); 1587 | n = 3; 1588 | m = 1; 1589 | xopt[0] = 1.0/SQRT(3.0); 1590 | xopt[1] = 1.0/SQRT(6.0); 1591 | xopt[2] = -0.33333333333333331; 1592 | break; 1593 | 1594 | case 4: 1595 | /* Weak version of Rosenbrock's problem. */ 1596 | PRT("Output from test problem 4 (Weak Rosenbrock)"); 1597 | n = 2; 1598 | m = 0; 1599 | xopt[0] = -1.0; 1600 | xopt[1] = 1.0; 1601 | break; 1602 | 1603 | case 5: 1604 | /* Intermediate version of Rosenbrock's problem. */ 1605 | PRT("Output from test problem 5 (Intermediate Rosenbrock)"); 1606 | n = 2; 1607 | m = 0; 1608 | xopt[0] = -1.0; 1609 | xopt[1] = 1.0; 1610 | break; 1611 | 1612 | case 6: 1613 | /* This problem is taken from Fletcher's book Practical Methods of 1614 | Optimization and has the equation number (9.1.15). */ 1615 | PRT("Output from test problem 6 (Equation (9.1.15) in Fletcher)"); 1616 | n = 2; 1617 | m = 2; 1618 | xopt[0] = SQRT(0.5); 1619 | xopt[1] = xopt[0]; 1620 | break; 1621 | 1622 | case 7: 1623 | /* This problem is taken from Fletcher's book Practical Methods of 1624 | Optimization and has the equation number (14.4.2). */ 1625 | PRT("Output from test problem 7 (Equation (14.4.2) in Fletcher)"); 1626 | n = 3; 1627 | m = 3; 1628 | xopt[0] = 0.0; 1629 | xopt[1] = -3.0; 1630 | xopt[2] = -3.0; 1631 | break; 1632 | 1633 | case 8: 1634 | /* This problem is taken from page 66 of Hock and Schittkowski's book 1635 | Test Examples for Nonlinear Programming Codes. It is their test 1636 | problem Number 43, and has the name Rosen-Suzuki. */ 1637 | PRT("Output from test problem 8 (Rosen-Suzuki)"); 1638 | n = 4; 1639 | m = 3; 1640 | xopt[0] = 0.0; 1641 | xopt[1] = 1.0; 1642 | xopt[2] = 2.0; 1643 | xopt[3] = -1.0; 1644 | break; 1645 | 1646 | case 9: 1647 | /* This problem is taken from page 111 of Hock and Schittkowski's book 1648 | Test Examples for Nonlinear Programming Codes. It is their test 1649 | problem Number 100. */ 1650 | PRT("Output from test problem 9 (Hock and Schittkowski 100)"); 1651 | n = 7; 1652 | m = 4; 1653 | xopt[0] = 2.330499; 1654 | xopt[1] = 1.951372; 1655 | xopt[2] = -0.4775414; 1656 | xopt[3] = 4.365726; 1657 | xopt[4] = -0.624487; 1658 | xopt[5] = 1.038131; 1659 | xopt[6] = 1.594227; 1660 | break; 1661 | 1662 | case 10: 1663 | default: 1664 | /* This problem is taken from page 415 of Luenberger's book Applied 1665 | Nonlinear Programming. It is to maximize the area of a hexagon of unit 1666 | diameter. */ 1667 | PRT("Output from test problem 10 (Hexagon area)"); 1668 | n = 9; 1669 | m = 14; 1670 | break; 1671 | 1672 | } 1673 | 1674 | # undef PRT 1675 | 1676 | for (icase = 1; icase <= 2; ++icase) { 1677 | for (i = 1; i <= n; ++i) { 1678 | x[i - 1] = 1.0; 1679 | } 1680 | rhobeg = 0.5; 1681 | rhoend = ((icase == 2) ? 1e-4 : 0.001); 1682 | iprint = 1; 1683 | maxfun = 2000; 1684 | #if defined(TESTING_REVCOM) 1685 | testing_revcom(n, m, rhobeg, rhoend, iprint, maxfun, x); 1686 | #elif defined(TESTING_FWRAP) 1687 | cobyla_(&n, &m, x, &rhobeg, &rhoend, &iprint, &maxfun, w, iact); 1688 | #else 1689 | cobyla(n, m, calcfc, NULL, x, rhobeg, rhoend, iprint, &maxfun, w, iact); 1690 | #endif 1691 | if (nprob == 10) { 1692 | tempa = x[0] + x[2] + x[4] + x[6]; 1693 | tempb = x[1] + x[3] + x[5] + x[7]; 1694 | tempc = 0.5/SQRT(tempa*tempa + tempb*tempb); 1695 | tempd = tempc*SQRT(3.0); 1696 | xopt[0] = tempd*tempa + tempc*tempb; 1697 | xopt[1] = tempd*tempb - tempc*tempa; 1698 | xopt[2] = tempd*tempa - tempc*tempb; 1699 | xopt[3] = tempd*tempb + tempc*tempa; 1700 | for (i = 1; i <= 4; ++i) { 1701 | xopt[i + 3] = xopt[i - 1]; 1702 | } 1703 | } 1704 | temp = 0.0; 1705 | for (i = 1; i <= n; ++i) { 1706 | r1 = x[i - 1] - xopt[i - 1]; 1707 | temp += r1*r1; 1708 | } 1709 | fprintf(stdout, "\n Least squares error in variables =%16.6E\n", 1710 | (double)SQRT(temp)); 1711 | } 1712 | fprintf(stdout, " ----------------------------------------------" 1713 | "--------------------\n"); 1714 | } 1715 | return 0; 1716 | } 1717 | 1718 | void 1719 | calcfc_(INTEGER* n, INTEGER* m, const REAL x[], REAL* f, REAL con[]) 1720 | { 1721 | *f = calcfc(*n, *m, x, con, NULL); 1722 | } 1723 | 1724 | static REAL 1725 | calcfc(INTEGER n, INTEGER m, const REAL x[], REAL con[], void* data) 1726 | { 1727 | REAL r1, r2, r3, r4, r5, r6, r7, fc; 1728 | 1729 | #define POW2(x) ((x)*(x)) 1730 | #define C(x) FLT(x) 1731 | #define CON(a1) con[a1 - 1] 1732 | #define X(a1) x[a1 - 1] 1733 | 1734 | 1735 | /* Beware that order of operations may affect the result (whithin rounding 1736 | errors). I have tried to keep the same ordering as F2C which takes care 1737 | of that, in particular when converting expressions involving powers. */ 1738 | 1739 | switch (nprob) { 1740 | 1741 | case 1: /* Test problem 1 (Simple quadratic) */ 1742 | r1 = X(1) + C(1.0); 1743 | r2 = X(2); 1744 | fc = C(10.0)*(r1*r1) + (r2*r2); 1745 | break; 1746 | 1747 | case 2: /* Test problem 2 (2D unit circle calculation) */ 1748 | fc = X(1)*X(2); 1749 | CON(1) = C(1.0) - X(1)*X(1) - X(2)*X(2); 1750 | break; 1751 | 1752 | case 3: /* Test problem 3 (3D ellipsoid calculation) */ 1753 | fc = X(1)*X(2)*X(3); 1754 | CON(1) = C(1.0) - (X(1)*X(1)) - C(2.0)*(X(2)*X(2)) 1755 | - C(3.0)*(X(3)*X(3)); 1756 | break; 1757 | 1758 | case 4: /* Test problem 4 (Weak Rosenbrock) */ 1759 | r2 = X(1); 1760 | r1 = r2*r2 - X(2); 1761 | r3 = X(1) + C(1.0); 1762 | fc = r1*r1 + r3*r3; 1763 | break; 1764 | 1765 | case 5: /* Test problem 5 (Intermediate Rosenbrock) */ 1766 | r2 = X(1); 1767 | r1 = r2*r2 - X(2); 1768 | r3 = X(1) + C(1.0); 1769 | fc = r1*r1*C(10.0) + r3*r3; 1770 | break; 1771 | 1772 | case 6: /* Test problem 6 (Equation (9.1.15) in Fletcher's book) */ 1773 | fc = -X(1) - X(2); 1774 | r1 = X(1); 1775 | CON(1) = X(2) - r1*r1; 1776 | r1 = X(1); 1777 | r2 = X(2); 1778 | CON(2) = C(1.0) - r1*r1 - r2*r2; 1779 | break; 1780 | 1781 | case 7: /* Test problem 7 (Equation (14.4.2) in Fletcher's book) */ 1782 | fc = X(3); 1783 | CON(1) = X(1)*C(5.0) - X(2) + X(3); 1784 | r1 = X(1); 1785 | r2 = X(2); 1786 | CON(2) = X(3) - r1*r1 - r2*r2 - X(2)*C(4.0); 1787 | CON(3) = X(3) - X(1)*C(5.0) - X(2); 1788 | break; 1789 | 1790 | case 8: /* Test problem 8 (Rosen-Suzuki) */ 1791 | r1 = X(1); 1792 | r2 = X(2); 1793 | r3 = X(3); 1794 | r4 = X(4); 1795 | fc = r1*r1 + r2*r2 + r3*r3*C(2.0) + r4*r4 - X(1)*C(5.0) - X(2)*C(5.0) 1796 | - X(3)*C(21.0) + X(4)*C(7.0); 1797 | r1 = X(1); 1798 | r2 = X(2); 1799 | r3 = X(3); 1800 | r4 = X(4); 1801 | CON(1) = C(8.0) - r1*r1 - r2*r2 - r3*r3 - r4*r4 - X(1) + X(2) - X(3) 1802 | + X(4); 1803 | r1 = X(1); 1804 | r2 = X(2); 1805 | r3 = X(3); 1806 | r4 = X(4); 1807 | CON(2) = C(10.0) - r1*r1 - r2*r2*C(2.0) - r3*r3 - r4*r4*C(2.0) + X(1) 1808 | + X(4); 1809 | r1 = X(1); 1810 | r2 = X(2); 1811 | r3 = X(3); 1812 | CON(3) = C(5.0) - r1*r1*C(2.0) - r2*r2 - r3*r3 - X(1)*C(2.0) + X(2) + X(4); 1813 | break; 1814 | 1815 | case 9: /* Test problem 9 (Hock and Schittkowski 100) */ 1816 | r1 = X(1) - C(10.0); 1817 | r2 = X(2) - C(12.0); 1818 | r3 = X(3); 1819 | r3 *= r3; 1820 | r4 = X(4) - C(11.0); 1821 | r5 = X(5); 1822 | r5 *= r5; 1823 | r6 = X(6); 1824 | r7 = X(7); 1825 | r7 *= r7; 1826 | fc = r1*r1 + r2*r2*C(5.0) + r3*r3 + r4*r4*C(3.0) + r5*(r5*r5)*C(10.0) 1827 | + r6*r6*C(7.0) + r7*r7 - X(6)*C(4.0)*X(7) - X(6)*C(10.0) - X(7)*C(8.0); 1828 | r1 = X(1); 1829 | r2 = X(2); 1830 | r2 *= r2; 1831 | r3 = X(4); 1832 | CON(1) = C(127.0) - r1*r1*C(2.0) - r2*r2*C(3.0) - X(3) - r3*r3*C(4.0) 1833 | - X(5)*C(5.0); 1834 | r1 = X(3); 1835 | CON(2) = C(282.0) - X(1)*C(7.0) - X(2)*C(3.0) - r1*r1*C(10.0) 1836 | - X(4) + X(5); 1837 | r1 = X(2); 1838 | r2 = X(6); 1839 | CON(3) = C(196.0) - X(1)*C(23.0) - r1*r1 - r2*r2*C(6.0) + X(7)*C(8.0); 1840 | r1 = X(1); 1841 | r2 = X(2); 1842 | r3 = X(3); 1843 | CON(4) = r1*r1*-C(4.0) - r2*r2 + X(1)*C(3.0)*X(2) - r3*r3*C(2.0) 1844 | - X(6)*C(5.0) + X(7)*C(11.0); 1845 | break; 1846 | 1847 | case 10: /* Test problem 10 (Hexagon area) */ 1848 | default: 1849 | fc = -C(0.5)*(X(1)*X(4) - X(2)*X(3) + X(3)*X(9) - X(5)*X(9) + X(5)*X(8) 1850 | - X(6)*X(7)); 1851 | r1 = X(3); 1852 | r2 = X(4); 1853 | CON(1) = C(1.0) - r1*r1 - r2*r2; 1854 | r1 = X(9); 1855 | CON(2) = C(1.0) - r1*r1; 1856 | r1 = X(5); 1857 | r2 = X(6); 1858 | CON(3) = C(1.0) - r1*r1 - r2*r2; 1859 | r1 = X(1); 1860 | r2 = X(2) - X(9); 1861 | CON(4) = C(1.0) - r1*r1 - r2*r2; 1862 | r1 = X(1) - X(5); 1863 | r2 = X(2) - X(6); 1864 | CON(5) = C(1.0) - r1*r1 - r2*r2; 1865 | r1 = X(1) - X(7); 1866 | r2 = X(2) - X(8); 1867 | CON(6) = C(1.0) - r1*r1 - r2*r2; 1868 | r1 = X(3) - X(5); 1869 | r2 = X(4) - X(6); 1870 | CON(7) = C(1.0) - r1*r1 - r2*r2; 1871 | r1 = X(3) - X(7); 1872 | r2 = X(4) - X(8); 1873 | CON(8) = C(1.0) - r1*r1 - r2*r2; 1874 | r1 = X(7); 1875 | r2 = X(8) - X(9); 1876 | CON(9) = C(1.0) - r1*r1 - r2*r2; 1877 | CON(10) = X(1)*X(4) - X(2)*X(3); 1878 | CON(11) = X(3)*X(9); 1879 | CON(12) = -X(5)*X(9); 1880 | CON(13) = X(5)*X(8) - X(6)*X(7); 1881 | CON(14) = X(9); 1882 | } 1883 | #undef POW2 1884 | #undef C 1885 | #undef CON 1886 | #undef X 1887 | 1888 | return fc; 1889 | } 1890 | 1891 | #ifdef TESTING_REVCOM 1892 | static void 1893 | testing_revcom(INTEGER n, INTEGER m, REAL rhobeg, REAL rhoend, 1894 | INTEGER iprint, INTEGER maxfun, REAL x[]) 1895 | { 1896 | REAL f; 1897 | REAL* c; 1898 | cobyla_context_t* ctx; 1899 | int status; 1900 | const char* reason; 1901 | 1902 | if (m > 0) { 1903 | c = (REAL*)malloc(m*sizeof(REAL)); 1904 | if (c == NULL) { 1905 | goto enomem; 1906 | } 1907 | } else { 1908 | c = NULL; 1909 | } 1910 | ctx = cobyla_create(n, m, rhobeg, rhoend, iprint, maxfun); 1911 | if (ctx == NULL) { 1912 | if (errno == ENOMEM) { 1913 | goto enomem; 1914 | } else { 1915 | goto einval; 1916 | } 1917 | } 1918 | status = cobyla_get_status(ctx); 1919 | while (status == COBYLA_ITERATE) { 1920 | f = calcfc(n, m, x, c, NULL); 1921 | status = cobyla_iterate(ctx, f, x, c); 1922 | } 1923 | cobyla_delete(ctx); 1924 | #if 0 1925 | if (status == COBYLA_SUCCESS) { 1926 | return; 1927 | } 1928 | reason = cobyla_reason(status); 1929 | #else 1930 | return; 1931 | #endif 1932 | 1933 | error: 1934 | fprintf(stderr, "Something work occured in COBYLA: %s\n", reason); 1935 | return; 1936 | 1937 | enomem: 1938 | reason = "insufficient memory"; 1939 | goto error; 1940 | 1941 | einval: 1942 | reason = "invalid parameters"; 1943 | goto error; 1944 | } 1945 | #endif /* TESTING_REVCOM */ 1946 | 1947 | #endif /* TESTING */ 1948 | 1949 | #endif /* _COBYLA_PART2 */ 1950 | 1951 | /*---------------------------------------------------------------------------*/ 1952 | -------------------------------------------------------------------------------- /cobyla/cobyla.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cobyla.h - 3 | * 4 | * Definitions for Mike Powell's COBYLA algorithm for minimizing a function of 5 | * a few variables. The method is "derivatives free" (only the function values 6 | * are needed) and accounts for constraints on the variables. The algorithm is 7 | * described in: 8 | * 9 | * M.J.D. Powell, "A direct search optimization method that models the 10 | * objective and constraint functions by linear interpolation," in Advances 11 | * in Optimization and Numerical Analysis Mathematics and Its Applications, 12 | * vol. 275 (eds. Susana Gomez and Jean-Pierre Hennart), Kluwer Academic 13 | * Publishers, pp. 51-67 (1994). 14 | * 15 | * The present code is based on the original FORTRAN version written by Mike 16 | * Powell who kindly provides his code on demand and has been converted to C by 17 | * É. Thiébaut. 18 | * 19 | * Copyright (c) 1992, Mike Powell (FORTRAN version). 20 | * Copyright (c) 2015, Éric Thiébaut (C version). 21 | * 22 | * Rémi Lafage (2021): copied from https://github.com/emmt/Algorithms/tree/master/cobyla 23 | * cobyla() was renamed raw_cobyla() to avoid name clash with NlOpt implementation 24 | * 25 | */ 26 | 27 | #ifndef _COBYLA_H 28 | #define _COBYLA_H 1 29 | 30 | #ifndef LOGICAL 31 | # define LOGICAL int 32 | #endif 33 | 34 | #ifndef INTEGER 35 | # define INTEGER long 36 | #endif 37 | 38 | #undef REAL 39 | #ifdef SINGLE_PRECISION 40 | # define REAL float 41 | #else 42 | # define REAL double 43 | #endif 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | /* Prototype of the objective function assumed by the COBYLA routine. The 50 | returned value is the function value at X, N is the number of variables, M 51 | is the number of constraints, X are the current values of the variables and 52 | CON is to store the M constraints. DATA is anything needed by the function 53 | (unused by COBYLA itself). */ 54 | typedef REAL 55 | cobyla_calcfc(INTEGER n, INTEGER m, const REAL x[], REAL con[], void* data); 56 | 57 | /* 58 | * This subroutine minimizes an objective function F(X) subject to M inequality 59 | * constraints on X, where X is a vector of variables that has N components. 60 | * The algorithm employs linear approximations to the objective and constraint 61 | * functions, the approximations being formed by linear interpolation at N+1 62 | * points in the space of the variables. We regard these interpolation points 63 | * as vertices of a simplex. The parameter RHO controls the size of the 64 | * simplex and it is reduced automatically from RHOBEG to RHOEND. For each RHO 65 | * the subroutine tries to achieve a good vector of variables for the current 66 | * size, and then RHO is reduced until the value RHOEND is reached. Therefore 67 | * RHOBEG and RHOEND should be set to reasonable initial changes to and the 68 | * required accuracy in the variables respectively, but this accuracy should be 69 | * viewed as a subject for experimentation because it is not guaranteed. The 70 | * subroutine has an advantage over many of its competitors, however, which is 71 | * that it treats each constraint individually when calculating a change to the 72 | * variables, instead of lumping the constraints together into a single penalty 73 | * function. The name of the subroutine is derived from the phrase Constrained 74 | * Optimization BY Linear Approximations. 75 | * 76 | * The user must set the values of N, M, RHOBEG and RHOEND, and must provide an 77 | * initial vector of variables in X. Further, the value of IPRINT should be 78 | * set to 0, 1, 2 or 3, which controls the amount of printing during the 79 | * calculation. Specifically, there is no output if IPRINT=0 and there is 80 | * output only at the end of the calculation if IPRINT=1. Otherwise each new 81 | * value of RHO and SIGMA is printed. Further, the vector of variables and 82 | * some function information are given either when RHO is reduced or when each 83 | * new value of F(X) is computed in the cases IPRINT=2 or IPRINT=3 84 | * respectively. Here SIGMA is a penalty parameter, it being assumed that a 85 | * change to X is an improvement if it reduces the merit function: 86 | * 87 | * F(X)+SIGMA*MAX(0.0,-C1(X),-C2(X),...,-CM(X)), 88 | * 89 | * where C1,C2,...,CM denote the constraint functions that should become 90 | * nonnegative eventually, at least to the precision of RHOEND. In the 91 | * printed output the displayed term that is multiplied by SIGMA is 92 | * called MAXCV, which stands for 'MAXimum Constraint Violation'. The 93 | * argument MAXFUN is an integer variable that must be set by the user to a 94 | * limit on the number of calls of CALCFC, the purpose of this routine being 95 | * given below. The value of MAXFUN will be altered to the number of calls 96 | * of CALCFC that are made. The arguments W and IACT provide real and 97 | * integer arrays that are used as working space. Their lengths must be at 98 | * least N*(3*N+2*M+11)+4*M+6 and M+1 respectively. 99 | * 100 | * In order to define the objective and constraint functions, we require a 101 | * subroutine that has the name and arguments 102 | * 103 | * SUBROUTINE CALCFC (N,M,X,F,CON) 104 | * DIMENSION X(*),CON(*) . 105 | * 106 | * The values of N and M are fixed and have been defined already, while X is 107 | * now the current vector of variables. The subroutine should return the 108 | * objective and constraint functions at X in F and CON(1),CON(2), ...,CON(M). 109 | * Note that we are trying to adjust X so that F(X) is as small as possible 110 | * subject to the constraint functions being nonnegative. 111 | */ 112 | 113 | 114 | extern int 115 | raw_cobyla(INTEGER n, INTEGER m, 116 | cobyla_calcfc* calcfc, void* calcfc_data, 117 | REAL x[], REAL rhobeg, REAL rhoend, 118 | INTEGER iprint, INTEGER* maxfun, 119 | REAL w[], INTEGER iact[]); 120 | 121 | /* Possible values returned by `cobyla`, `cobyla_get_status` and 122 | `cobyla_iterate`: */ 123 | #define COBYLA_INITIAL_ITERATE (2) /* only used internally */ 124 | #define COBYLA_ITERATE (1) /* user requested to compute 125 | F(X) and C(X) */ 126 | #define COBYLA_SUCCESS (0) /* algorithm converged */ 127 | #define COBYLA_ROUNDING_ERRORS (-1) /* rounding errors prevent 128 | progress */ 129 | #define COBYLA_TOO_MANY_EVALUATIONS (-2) /* too many evaluations */ 130 | #define COBYLA_BAD_ADDRESS (-3) /* illegal address */ 131 | #define COBYLA_CORRUPTED (-4) /* corrupted workspace */ 132 | 133 | /* Opaque structure used by the reverse communication variant of COBYLA. */ 134 | typedef struct _cobyla_context cobyla_context_t; 135 | 136 | /* Allocate a new reverse communication workspace for COBYLA algorithm. The 137 | returned address is `NULL` to indicate an error due to either invalid 138 | parameters (external variable `errno` set to `EINVAL`), or insufficient 139 | memory (external variable `errno` set to `ENOMEM`). When no longer needed, 140 | the workspace must be deleted with `cobyla_delete`. 141 | 142 | A typical usage is: 143 | ``` 144 | REAL x[N], c[M], f; 145 | cobyla_context_t* ctx; 146 | x[...] = ...; // initial solution 147 | ctx = cobyla_create(N, M, RHOBEG, RHOEND, IPRINT, MAXFUN); 148 | status = cobyla_get_status(ctx); 149 | while (status == COBYLA_ITERATE) { 150 | f = ...; // compute function value at X 151 | c[...] = ...; // compute constraints at X 152 | status = cobyla_iterate(ctx, f, x, c); 153 | } 154 | cobyla_delete(ctx); 155 | if (status != COBYLA_SUCCESS) { 156 | fprintf(stderr, "Something wrong occured in COBYLA: %s\n", 157 | cobyla_reason(status)); 158 | } 159 | ``` 160 | */ 161 | extern cobyla_context_t* 162 | cobyla_create(INTEGER n, INTEGER m, REAL rhobeg, REAL rhoend, 163 | INTEGER iprint, INTEGER maxfun); 164 | 165 | /* Release ressources allocated for COBYLA reverse communication workspace. 166 | Argument can be `NULL`. */ 167 | extern void 168 | cobyla_delete(cobyla_context_t* ctx); 169 | 170 | /* Perform the next iteration of the reverse communication variant of the 171 | COBYLA algorithm. On entry, the workspace status must be `COBYLA_ITERATE`, 172 | `f` and `c` are the function value and the constraints at `x`. On exit, the 173 | returned value (the new workspace status) is: `COBYLA_ITERATE` if a new 174 | trial point has been stored in `x` and if user is requested to compute the 175 | function value and the constraints at the new point; `COBYLA_SUCCESS` if 176 | algorithm has converged and `x` has been set with the variables at the 177 | solution (the corresponding function value can be retrieved with 178 | `cobyla_get_last_f`); anything else indicates an error (see `cobyla_reason` 179 | for an explanatory message). */ 180 | extern int 181 | cobyla_iterate(cobyla_context_t* ctx, REAL f, REAL x[], REAL c[]); 182 | 183 | /* Restart COBYLA algorithm using the same parameters. The return value is 184 | the new status of the algorithm, see `cobyla_get_status` for details. */ 185 | extern int 186 | cobyla_restart(cobyla_context_t* ctx); 187 | 188 | /* Get the current status of the algorithm. Result is: `COBYLA_ITERATE` if 189 | user is requested to compute F(X) and C(X); `COBYLA_SUCCESS` if algorithm 190 | has converged; anything else indicates an error (see `cobyla_reason` for an 191 | explanatory message). */ 192 | extern int 193 | cobyla_get_status(const cobyla_context_t* ctx); 194 | 195 | /* Get the current number of function evaluations. Result is -1 if something 196 | is wrong (e.g. CTX is NULL), nonnegative otherwise. */ 197 | extern INTEGER 198 | cobyla_get_nevals(const cobyla_context_t* ctx); 199 | 200 | /* Get the current size of the trust region. Result is 0 if algorithm has not 201 | yet been started (before first iteration), -1 if something is wrong 202 | (e.g. CTX is NULL), strictly positive otherwise. */ 203 | extern REAL 204 | cobyla_get_rho(const cobyla_context_t* ctx); 205 | 206 | /* Get the last function value. Upon convergence of `cobyla_iterate` 207 | (i.e. return with status `COBYLA_SUCCESS`), this value corresponds to the 208 | function at the solution; otherwise, this value corresponds to the previous 209 | set of variables. */ 210 | extern REAL 211 | cobyla_get_last_f(const cobyla_context_t* ctx); 212 | 213 | /* Get a textual explanation of the status returned by `cobyla`, 214 | `cobyla_get_status` and `cobyla_iterate`. */ 215 | extern const char* 216 | cobyla_reason(int status); 217 | 218 | 219 | /*---------------------------------------------------------------------------*/ 220 | /* FORTRAN SUPPORT */ 221 | 222 | /* Depending on your FORTRAN compiler, the names of the compiled functions 223 | may have to be modified. The various possibilities can be chosen via the 224 | macro FORTRAN_LINKAGE: 225 | 226 | -UFORTRAN_LINKAGE (or FORTRAN_LINKAGE undefined) 227 | No support for FORTRAN will be compiled. 228 | 229 | -DFORTRAN_LINKAGE=0 FORTRAN link name is the same as with the C 230 | compiler. 231 | 232 | -DFORTRAN_LINKAGE=1 FORTRAN link name is is the function name in upper 233 | case letters (for instance, `foo` yields `FOO`). 234 | 235 | -DFORTRAN_LINKAGE=2 FORTRAN link name is the function name suffixed 236 | with an underscore (for instance, `foo` yields 237 | `foo_`). 238 | 239 | -DFORTRAN_LINKAGE=3 FORTRAN link name is the function name in upper 240 | case letters and suffixed with an underscore 241 | (for instance, `foo` yields `FOO_`). 242 | */ 243 | 244 | #ifdef FORTRAN_LINKAGE 245 | 246 | # if FORTRAN_LINKAGE == 0 247 | # define FORTRAN_NAME(a,A) a 248 | # error names will clash 249 | # elif FORTRAN_LINKAGE == 1 250 | # define FORTRAN_NAME(a,A) A 251 | # elif FORTRAN_LINKAGE == 2 252 | # define FORTRAN_NAME(a,A) a##_ 253 | # elif FORTRAN_LINKAGE == 3 254 | # define FORTRAN_NAME(a,A) A##_ 255 | # else 256 | # error unsupported FORTRAN linkage 257 | # endif 258 | 259 | /* 260 | * Subroutine variant designed to be callable from FORTRAN code. Usage is 261 | * similar to that of `cobyla` except that everything is passed by address and 262 | * that, in order to define the objective and constraint functions, we require 263 | * a subroutine that has the name and arguments: 264 | * 265 | * SUBROUTINE CALCFC (N,M,X,F,CON) 266 | * DIMENSION X(*),CON(*) 267 | * 268 | * The values of N and M are fixed and have been defined already, while X is 269 | * now the current vector of variables. The subroutine should return the 270 | * objective and constraint functions at X in F and CON(1),CON(2), ...,CON(M). 271 | * Note that we are trying to adjust X so that F(X) is as small as possible 272 | * subject to the constraint functions being nonnegative. 273 | */ 274 | extern int 275 | FORTRAN_NAME(cobyla,COBYLA)(INTEGER* n, INTEGER* m, REAL x[], 276 | REAL* rhobeg, REAL* rhoend, 277 | INTEGER* iprint, INTEGER* maxfun, 278 | REAL w[], INTEGER iact[]); 279 | 280 | #endif /* FORTRAN_LINKAGE */ 281 | 282 | #ifdef __cplusplus 283 | } 284 | #endif 285 | 286 | #endif /* _COBYLA_H */ 287 | 288 | /*---------------------------------------------------------------------------*/ 289 | -------------------------------------------------------------------------------- /cobyla/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "directory": "/home/rlafage/workspace/cobyla/build", 4 | "command": "/usr/bin/cc -I/home/rlafage/workspace/cobyla/cobyla -o CMakeFiles/cobyla.dir/cobyla.c.o -c /home/rlafage/workspace/cobyla/cobyla/cobyla.c", 5 | "file": "/home/rlafage/workspace/cobyla/cobyla/cobyla.c" 6 | } 7 | ] -------------------------------------------------------------------------------- /cobyla/nlopt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0.0) 2 | project (cobyla) 3 | 4 | include (CheckIncludeFiles) 5 | include (CheckFunctionExists) 6 | include (CheckTypeSize) 7 | include (CheckCCompilerFlag) 8 | include (CheckCXXSymbolExists) 9 | include (CheckCSourceCompiles) 10 | include (CheckCXXCompilerFlag) 11 | include (CheckLibraryExists) 12 | 13 | check_include_file (getopt.h HAVE_GETOPT_H) 14 | check_include_file (unistd.h HAVE_UNISTD_H) 15 | check_include_file (stdint.h HAVE_STDINT_H) 16 | check_include_file (time.h HAVE_TIME_H) 17 | check_include_file (sys/time.h HAVE_SYS_TIME_H) 18 | if (HAVE_TIME_H AND HAVE_SYS_TIME_H) 19 | set (TIME_WITH_SYS_TIME TRUE) 20 | endif () 21 | check_function_exists (getpid HAVE_GETPID) 22 | check_function_exists (syscall HAVE_GETTID_SYSCALL) 23 | check_function_exists (isinf HAVE_ISINF) 24 | check_function_exists (isnan HAVE_ISNAN) 25 | check_function_exists (gettimeofday HAVE_GETTIMEOFDAY) 26 | check_function_exists (qsort_r HAVE_QSORT_R) 27 | check_function_exists (time HAVE_TIME) 28 | check_function_exists (copysign HAVE_COPYSIGN) 29 | check_function_exists (getopt HAVE_GETOPT) 30 | check_type_size ("uint32_t" SIZEOF_UINT32_T) 31 | set (HAVE_UINT32_T ${SIZEOF_UINT32_T}) 32 | check_type_size ("unsigned int" SIZEOF_UNSIGNED_INT) 33 | check_type_size ("unsigned long" SIZEOF_UNSIGNED_LONG) 34 | 35 | check_library_exists ("m" sqrt "" HAVE_LIBM) 36 | if (HAVE_LIBM) 37 | set (M_LIBRARY m) 38 | endif() 39 | 40 | configure_file (${CMAKE_CURRENT_SOURCE_DIR}/nlopt_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/nlopt_config.h IMMEDIATE) 41 | 42 | add_library (cobyla cobyla.c) 43 | 44 | target_include_directories (cobyla PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -------------------------------------------------------------------------------- /cobyla/nlopt/README.md: -------------------------------------------------------------------------------- 1 | To generate compile commands json file required by c2rust in top directory 2 | 3 | > mkdir build 4 | > cd build 5 | > cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ../cobyla/nlopt 6 | > cp compile_commands.json ../cobyla/nlopt/compile_commands.json 7 | 8 | Then rust generation from C 9 | 10 | > cd ../cobyla/nlopt 11 | > c2rust transpile compile_commands.json -------------------------------------------------------------------------------- /cobyla/nlopt/cobyla.h: -------------------------------------------------------------------------------- 1 | /* cobyla : contrained optimization by linear approximation */ 2 | 3 | /* 4 | * Copyright (c) 1992, Michael J. D. Powell (M.J.D.Powell@damtp.cam.ac.uk) 5 | * Copyright (c) 2004, Jean-Sebastien Roy (js@jeannot.org) 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a 8 | * copy of this software and associated documentation files (the 9 | * "Software"), to deal in the Software without restriction, including 10 | * without limitation the rights to use, copy, modify, merge, publish, 11 | * distribute, sublicense, and/or sell copies of the Software, and to 12 | * permit persons to whom the Software is furnished to do so, subject to 13 | * the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included 16 | * in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | /* 28 | * This software is a C version of COBYLA2, a contrained optimization by linear 29 | * approximation package developed by Michael J. D. Powell in Fortran. 30 | * 31 | * The original source code can be found at : 32 | * http://plato.la.asu.edu/topics/problems/nlores.html 33 | */ 34 | 35 | /* $Jeannot: cobyla.h,v 1.10 2004/04/18 09:51:37 js Exp $ */ 36 | 37 | #ifndef _COBYLA_ 38 | #define _COBYLA_ 39 | 40 | #include "nlopt.h" 41 | #include "nlopt-util.h" 42 | 43 | /* NLopt-style interface function */ 44 | nlopt_result cobyla_minimize(unsigned n, nlopt_func f, void *f_data, 45 | unsigned m, nlopt_constraint *fc, 46 | unsigned p, nlopt_constraint *h, 47 | const double *lb, const double *ub, /* bounds */ 48 | double *x, /* in: initial guess, out: minimizer */ 49 | double *minf, 50 | nlopt_stopping *stop, 51 | const double *dx); 52 | 53 | #endif /* _COBYLA_ */ 54 | -------------------------------------------------------------------------------- /cobyla/nlopt/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "directory": "/home/rlafage/workspace/cobyla/build", 4 | "command": "/usr/bin/cc -I/home/rlafage/workspace/cobyla/cobyla -o CMakeFiles/cobyla.dir/cobyla.c.o -c /home/rlafage/workspace/cobyla/cobyla/cobyla.c", 5 | "file": "/home/rlafage/workspace/cobyla/cobyla/cobyla.c" 6 | } 7 | ] -------------------------------------------------------------------------------- /cobyla/nlopt/nlopt-util.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2014 Massachusetts Institute of Technology 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining 4 | * a copy of this software and associated documentation files (the 5 | * "Software"), to deal in the Software without restriction, including 6 | * without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to 9 | * the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef NLOPT_UTIL_H 24 | #define NLOPT_UTIL_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include "nlopt_config.h" 30 | 31 | #include "nlopt.h" 32 | 33 | /* workaround for Solaris + gcc 3.4.x bug (see configure.ac) */ 34 | #if defined(__GNUC__) && defined(REPLACEMENT_HUGE_VAL) 35 | # undef HUGE_VAL 36 | # define HUGE_VAL REPLACEMENT_HUGE_VAL 37 | #endif 38 | 39 | #ifndef HAVE_COPYSIGN 40 | /* not quite right for y == -0, but good enough for us */ 41 | # define copysign(x, y) ((y) < 0 ? -fabs(x) : fabs(x)) 42 | #elif !defined(__cplusplus) && __STDC_VERSION__ < 199901 43 | extern double copysign(double x, double y); /* may not be declared in C89 */ 44 | #endif 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif /* __cplusplus */ 49 | 50 | int nlopt_isinf(double x); 51 | int nlopt_isfinite(double x); 52 | int nlopt_istiny(double x); 53 | int nlopt_isnan(double x); 54 | 55 | /* re-entrant qsort, uses the BSD convention */ 56 | extern void nlopt_qsort_r(void *base_, size_t nmemb, size_t size, void *thunk, int (*compar) (void *, const void *, const void *)); 57 | 58 | /* seconds timer */ 59 | extern double nlopt_seconds(void); 60 | extern unsigned long nlopt_time_seed(void); 61 | 62 | /* pseudorandom number generation by Mersenne twister algorithm */ 63 | extern void nlopt_init_genrand(unsigned long s); 64 | extern double nlopt_urand(double a, double b); 65 | extern int nlopt_iurand(int n); 66 | extern double nlopt_nrand(double mean, double stddev); 67 | 68 | /* Sobol' low-discrepancy-sequence generation */ 69 | typedef struct nlopt_soboldata_s *nlopt_sobol; 70 | extern nlopt_sobol nlopt_sobol_create(unsigned sdim); 71 | extern void nlopt_sobol_destroy(nlopt_sobol s); 72 | extern void nlopt_sobol_next01(nlopt_sobol s, double *x); 73 | extern void nlopt_sobol_next(nlopt_sobol s, double *x, const double *lb, const double *ub); 74 | extern void nlopt_sobol_skip(nlopt_sobol s, unsigned n, double *x); 75 | 76 | /* stopping criteria */ 77 | typedef struct { 78 | unsigned n; 79 | double minf_max; 80 | double ftol_rel; 81 | double ftol_abs; 82 | double xtol_rel; 83 | const double *xtol_abs; 84 | const double *x_weights; 85 | int *nevals_p, maxeval; 86 | double maxtime, start; 87 | int *force_stop; 88 | char **stop_msg; /* pointer to msg string to update */ 89 | } nlopt_stopping; 90 | extern int nlopt_stop_f(const nlopt_stopping * stop, double f, double oldf); 91 | extern int nlopt_stop_ftol(const nlopt_stopping * stop, double f, double oldf); 92 | extern int nlopt_stop_x(const nlopt_stopping * stop, const double *x, const double *oldx); 93 | extern int nlopt_stop_dx(const nlopt_stopping * stop, const double *x, const double *dx); 94 | extern int nlopt_stop_xs(const nlopt_stopping * stop, const double *xs, const double *oldxs, const double *scale_min, const double *scale_max); 95 | extern int nlopt_stop_evals(const nlopt_stopping * stop); 96 | extern int nlopt_stop_time_(double start, double maxtime); 97 | extern int nlopt_stop_time(const nlopt_stopping * stop); 98 | extern int nlopt_stop_evalstime(const nlopt_stopping * stop); 99 | extern int nlopt_stop_forced(const nlopt_stopping * stop); 100 | 101 | /* like vsprintf, but reallocs p to whatever size is needed */ 102 | extern char *nlopt_vsprintf(char *p, const char *format, va_list ap); 103 | extern void nlopt_stop_msg(const nlopt_stopping * s, const char *format, ...) 104 | #ifdef __GNUC__ 105 | __attribute__ ((format(printf, 2, 3))) 106 | #endif 107 | ; 108 | 109 | /* for local optimizations, temporarily setting eval/time limits */ 110 | extern nlopt_result nlopt_optimize_limited(nlopt_opt opt, double *x, double *minf, int maxevals, double maxtime); 111 | 112 | /* data structure for nonlinear inequality or equality constraint 113 | (f <= 0 or f = 0, respectively). tol (>= 0) is a tolerance 114 | that is used for stopping criteria -- the point is considered 115 | "feasible" for purposes of stopping if the constraint is violated 116 | by at most tol. */ 117 | typedef struct { 118 | unsigned m; /* dimensional of constraint: mf maps R^n -> R^m */ 119 | nlopt_func f; /* one-dimensional constraint, requires m == 1 */ 120 | nlopt_mfunc mf; 121 | nlopt_precond pre; /* preconditioner for f (NULL if none or if mf) */ 122 | void *f_data; 123 | double *tol; 124 | } nlopt_constraint; 125 | 126 | extern unsigned nlopt_count_constraints(unsigned p, const nlopt_constraint * c); 127 | extern unsigned nlopt_max_constraint_dim(unsigned p, const nlopt_constraint * c); 128 | extern void nlopt_eval_constraint(double *result, double *grad, const nlopt_constraint * c, unsigned n, const double *x); 129 | 130 | /* rescale.c: */ 131 | double *nlopt_compute_rescaling(unsigned n, const double *dx); 132 | double *nlopt_new_rescaled(unsigned n, const double *s, const double *x); 133 | void nlopt_rescale(unsigned n, const double *s, const double *x, double *xs); 134 | void nlopt_unscale(unsigned n, const double *s, const double *x, double *xs); 135 | void nlopt_reorder_bounds(unsigned n, double *lb, double *ub); 136 | 137 | #ifdef __cplusplus 138 | } /* extern "C" */ 139 | #endif /* __cplusplus */ 140 | #endif 141 | -------------------------------------------------------------------------------- /cobyla/nlopt/nlopt.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2014 Massachusetts Institute of Technology 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining 4 | * a copy of this software and associated documentation files (the 5 | * "Software"), to deal in the Software without restriction, including 6 | * without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to 9 | * the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef NLOPT_H 24 | #define NLOPT_H 25 | 26 | #include /* for ptrdiff_t and size_t */ 27 | 28 | /* Change 0 to 1 to use stdcall convention under Win32 */ 29 | #if 0 && (defined(_WIN32) || defined(__WIN32__)) 30 | # if defined(__GNUC__) 31 | # define NLOPT_STDCALL __attribute__((stdcall)) 32 | # elif defined(_MSC_VER) || defined(_ICC) || defined(_STDCALL_SUPPORTED) 33 | # define NLOPT_STDCALL __stdcall 34 | # else 35 | # define NLOPT_STDCALL 36 | # endif 37 | #else 38 | # define NLOPT_STDCALL 39 | #endif 40 | 41 | /* for Windows compilers, you should add a line 42 | #define NLOPT_DLL 43 | when using NLopt from a DLL, in order to do the proper 44 | Windows importing nonsense. */ 45 | #if defined(NLOPT_DLL) && (defined(_WIN32) || defined(__WIN32__)) && !defined(__LCC__) 46 | /* annoying Windows syntax for calling functions in a DLL */ 47 | # if defined(NLOPT_DLL_EXPORT) 48 | # define NLOPT_EXTERN(T) extern __declspec(dllexport) T NLOPT_STDCALL 49 | # else 50 | # define NLOPT_EXTERN(T) extern __declspec(dllimport) T NLOPT_STDCALL 51 | # endif 52 | #else 53 | # define NLOPT_EXTERN(T) extern T NLOPT_STDCALL 54 | #endif 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif /* __cplusplus */ 59 | 60 | typedef double (*nlopt_func) (unsigned n, const double *x, 61 | double *gradient, /* NULL if not needed */ 62 | void *func_data); 63 | 64 | typedef void (*nlopt_mfunc) (unsigned m, double *result, unsigned n, const double *x, 65 | double *gradient, /* NULL if not needed */ 66 | void *func_data); 67 | 68 | /* A preconditioner, which preconditions v at x to return vpre. 69 | (The meaning of "preconditioning" is algorithm-dependent.) */ 70 | typedef void (*nlopt_precond) (unsigned n, const double *x, const double *v, double *vpre, void *data); 71 | 72 | typedef enum { 73 | /* Naming conventions: 74 | 75 | NLOPT_{G/L}{D/N}_* 76 | = global/local derivative/no-derivative optimization, 77 | respectively 78 | 79 | *_RAND algorithms involve some randomization. 80 | 81 | *_NOSCAL algorithms are *not* scaled to a unit hypercube 82 | (i.e. they are sensitive to the units of x) 83 | */ 84 | 85 | NLOPT_GN_DIRECT = 0, 86 | NLOPT_GN_DIRECT_L, 87 | NLOPT_GN_DIRECT_L_RAND, 88 | NLOPT_GN_DIRECT_NOSCAL, 89 | NLOPT_GN_DIRECT_L_NOSCAL, 90 | NLOPT_GN_DIRECT_L_RAND_NOSCAL, 91 | 92 | NLOPT_GN_ORIG_DIRECT, 93 | NLOPT_GN_ORIG_DIRECT_L, 94 | 95 | NLOPT_GD_STOGO, 96 | NLOPT_GD_STOGO_RAND, 97 | 98 | NLOPT_LD_LBFGS_NOCEDAL, 99 | 100 | NLOPT_LD_LBFGS, 101 | 102 | NLOPT_LN_PRAXIS, 103 | 104 | NLOPT_LD_VAR1, 105 | NLOPT_LD_VAR2, 106 | 107 | NLOPT_LD_TNEWTON, 108 | NLOPT_LD_TNEWTON_RESTART, 109 | NLOPT_LD_TNEWTON_PRECOND, 110 | NLOPT_LD_TNEWTON_PRECOND_RESTART, 111 | 112 | NLOPT_GN_CRS2_LM, 113 | 114 | NLOPT_GN_MLSL, 115 | NLOPT_GD_MLSL, 116 | NLOPT_GN_MLSL_LDS, 117 | NLOPT_GD_MLSL_LDS, 118 | 119 | NLOPT_LD_MMA, 120 | 121 | NLOPT_LN_COBYLA, 122 | 123 | NLOPT_LN_NEWUOA, 124 | NLOPT_LN_NEWUOA_BOUND, 125 | 126 | NLOPT_LN_NELDERMEAD, 127 | NLOPT_LN_SBPLX, 128 | 129 | NLOPT_LN_AUGLAG, 130 | NLOPT_LD_AUGLAG, 131 | NLOPT_LN_AUGLAG_EQ, 132 | NLOPT_LD_AUGLAG_EQ, 133 | 134 | NLOPT_LN_BOBYQA, 135 | 136 | NLOPT_GN_ISRES, 137 | 138 | /* new variants that require local_optimizer to be set, 139 | not with older constants for backwards compatibility */ 140 | NLOPT_AUGLAG, 141 | NLOPT_AUGLAG_EQ, 142 | NLOPT_G_MLSL, 143 | NLOPT_G_MLSL_LDS, 144 | 145 | NLOPT_LD_SLSQP, 146 | 147 | NLOPT_LD_CCSAQ, 148 | 149 | NLOPT_GN_ESCH, 150 | 151 | NLOPT_GN_AGS, 152 | 153 | NLOPT_NUM_ALGORITHMS /* not an algorithm, just the number of them */ 154 | } nlopt_algorithm; 155 | 156 | NLOPT_EXTERN(const char *) nlopt_algorithm_name(nlopt_algorithm a); 157 | 158 | /* nlopt_algorithm enum <-> string conversion */ 159 | NLOPT_EXTERN(const char *) nlopt_algorithm_to_string(nlopt_algorithm algorithm); 160 | NLOPT_EXTERN(nlopt_algorithm) nlopt_algorithm_from_string(const char *name); 161 | 162 | typedef enum { 163 | NLOPT_FAILURE = -1, /* generic failure code */ 164 | NLOPT_INVALID_ARGS = -2, 165 | NLOPT_OUT_OF_MEMORY = -3, 166 | NLOPT_ROUNDOFF_LIMITED = -4, 167 | NLOPT_FORCED_STOP = -5, 168 | NLOPT_NUM_FAILURES = -6, /* not a result, just the number of possible failures */ 169 | NLOPT_SUCCESS = 1, /* generic success code */ 170 | NLOPT_STOPVAL_REACHED = 2, 171 | NLOPT_FTOL_REACHED = 3, 172 | NLOPT_XTOL_REACHED = 4, 173 | NLOPT_MAXEVAL_REACHED = 5, 174 | NLOPT_MAXTIME_REACHED = 6, 175 | NLOPT_NUM_RESULTS /* not a result, just the number of possible successes */ 176 | } nlopt_result; 177 | 178 | /* nlopt_result enum <-> string conversion */ 179 | NLOPT_EXTERN(const char *) nlopt_result_to_string(nlopt_result algorithm); 180 | NLOPT_EXTERN(nlopt_result) nlopt_result_from_string(const char *name); 181 | 182 | #define NLOPT_MINF_MAX_REACHED NLOPT_STOPVAL_REACHED 183 | 184 | NLOPT_EXTERN(void) nlopt_srand(unsigned long seed); 185 | NLOPT_EXTERN(void) nlopt_srand_time(void); 186 | 187 | NLOPT_EXTERN(void) nlopt_version(int *major, int *minor, int *bugfix); 188 | 189 | /*************************** OBJECT-ORIENTED API **************************/ 190 | /* The style here is that we create an nlopt_opt "object" (an opaque pointer), 191 | then set various optimization parameters, and then execute the 192 | algorithm. In this way, we can add more and more optimization parameters 193 | (including algorithm-specific ones) without breaking backwards 194 | compatibility, having functions with zillions of parameters, or 195 | relying non-reentrantly on global variables.*/ 196 | 197 | struct nlopt_opt_s; /* opaque structure, defined internally */ 198 | typedef struct nlopt_opt_s *nlopt_opt; 199 | 200 | /* the only immutable parameters of an optimization are the algorithm and 201 | the dimension n of the problem, since changing either of these could 202 | have side-effects on lots of other parameters */ 203 | NLOPT_EXTERN(nlopt_opt) nlopt_create(nlopt_algorithm algorithm, unsigned n); 204 | NLOPT_EXTERN(void) nlopt_destroy(nlopt_opt opt); 205 | NLOPT_EXTERN(nlopt_opt) nlopt_copy(const nlopt_opt opt); 206 | 207 | NLOPT_EXTERN(nlopt_result) nlopt_optimize(nlopt_opt opt, double *x, double *opt_f); 208 | 209 | NLOPT_EXTERN(nlopt_result) nlopt_set_min_objective(nlopt_opt opt, nlopt_func f, void *f_data); 210 | NLOPT_EXTERN(nlopt_result) nlopt_set_max_objective(nlopt_opt opt, nlopt_func f, void *f_data); 211 | 212 | NLOPT_EXTERN(nlopt_result) nlopt_set_precond_min_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data); 213 | NLOPT_EXTERN(nlopt_result) nlopt_set_precond_max_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data); 214 | 215 | NLOPT_EXTERN(nlopt_algorithm) nlopt_get_algorithm(const nlopt_opt opt); 216 | NLOPT_EXTERN(unsigned) nlopt_get_dimension(const nlopt_opt opt); 217 | 218 | NLOPT_EXTERN(const char *) nlopt_get_errmsg(nlopt_opt opt); 219 | 220 | /* generic algorithm parameters: */ 221 | NLOPT_EXTERN(nlopt_result) nlopt_set_param(nlopt_opt opt, const char *name, double val); 222 | NLOPT_EXTERN(double) nlopt_get_param(const nlopt_opt opt, const char *name, double defaultval); 223 | NLOPT_EXTERN(int) nlopt_has_param(const nlopt_opt opt, const char *name); 224 | NLOPT_EXTERN(unsigned) nlopt_num_params(const nlopt_opt opt); 225 | NLOPT_EXTERN(const char *) nlopt_nth_param(const nlopt_opt opt, unsigned n); 226 | 227 | /* constraints: */ 228 | 229 | NLOPT_EXTERN(nlopt_result) nlopt_set_lower_bounds(nlopt_opt opt, const double *lb); 230 | NLOPT_EXTERN(nlopt_result) nlopt_set_lower_bounds1(nlopt_opt opt, double lb); 231 | NLOPT_EXTERN(nlopt_result) nlopt_set_lower_bound(nlopt_opt opt, int i, double lb); 232 | NLOPT_EXTERN(nlopt_result) nlopt_get_lower_bounds(const nlopt_opt opt, double *lb); 233 | NLOPT_EXTERN(nlopt_result) nlopt_set_upper_bounds(nlopt_opt opt, const double *ub); 234 | NLOPT_EXTERN(nlopt_result) nlopt_set_upper_bounds1(nlopt_opt opt, double ub); 235 | NLOPT_EXTERN(nlopt_result) nlopt_set_upper_bound(nlopt_opt opt, int i, double ub); 236 | NLOPT_EXTERN(nlopt_result) nlopt_get_upper_bounds(const nlopt_opt opt, double *ub); 237 | 238 | NLOPT_EXTERN(nlopt_result) nlopt_remove_inequality_constraints(nlopt_opt opt); 239 | NLOPT_EXTERN(nlopt_result) nlopt_add_inequality_constraint(nlopt_opt opt, nlopt_func fc, void *fc_data, double tol); 240 | NLOPT_EXTERN(nlopt_result) nlopt_add_precond_inequality_constraint(nlopt_opt opt, nlopt_func fc, nlopt_precond pre, void *fc_data, double tol); 241 | NLOPT_EXTERN(nlopt_result) nlopt_add_inequality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc fc, void *fc_data, const double *tol); 242 | 243 | NLOPT_EXTERN(nlopt_result) nlopt_remove_equality_constraints(nlopt_opt opt); 244 | NLOPT_EXTERN(nlopt_result) nlopt_add_equality_constraint(nlopt_opt opt, nlopt_func h, void *h_data, double tol); 245 | NLOPT_EXTERN(nlopt_result) nlopt_add_precond_equality_constraint(nlopt_opt opt, nlopt_func h, nlopt_precond pre, void *h_data, double tol); 246 | NLOPT_EXTERN(nlopt_result) nlopt_add_equality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc h, void *h_data, const double *tol); 247 | 248 | /* stopping criteria: */ 249 | 250 | NLOPT_EXTERN(nlopt_result) nlopt_set_stopval(nlopt_opt opt, double stopval); 251 | NLOPT_EXTERN(double) nlopt_get_stopval(const nlopt_opt opt); 252 | 253 | NLOPT_EXTERN(nlopt_result) nlopt_set_ftol_rel(nlopt_opt opt, double tol); 254 | NLOPT_EXTERN(double) nlopt_get_ftol_rel(const nlopt_opt opt); 255 | NLOPT_EXTERN(nlopt_result) nlopt_set_ftol_abs(nlopt_opt opt, double tol); 256 | NLOPT_EXTERN(double) nlopt_get_ftol_abs(const nlopt_opt opt); 257 | 258 | NLOPT_EXTERN(nlopt_result) nlopt_set_xtol_rel(nlopt_opt opt, double tol); 259 | NLOPT_EXTERN(double) nlopt_get_xtol_rel(const nlopt_opt opt); 260 | NLOPT_EXTERN(nlopt_result) nlopt_set_xtol_abs1(nlopt_opt opt, double tol); 261 | NLOPT_EXTERN(nlopt_result) nlopt_set_xtol_abs(nlopt_opt opt, const double *tol); 262 | NLOPT_EXTERN(nlopt_result) nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); 263 | NLOPT_EXTERN(nlopt_result) nlopt_set_x_weights1(nlopt_opt opt, double w); 264 | NLOPT_EXTERN(nlopt_result) nlopt_set_x_weights(nlopt_opt opt, const double *w); 265 | NLOPT_EXTERN(nlopt_result) nlopt_get_x_weights(const nlopt_opt opt, double *w); 266 | 267 | NLOPT_EXTERN(nlopt_result) nlopt_set_maxeval(nlopt_opt opt, int maxeval); 268 | NLOPT_EXTERN(int) nlopt_get_maxeval(const nlopt_opt opt); 269 | 270 | NLOPT_EXTERN(int) nlopt_get_numevals(const nlopt_opt opt); 271 | 272 | NLOPT_EXTERN(nlopt_result) nlopt_set_maxtime(nlopt_opt opt, double maxtime); 273 | NLOPT_EXTERN(double) nlopt_get_maxtime(const nlopt_opt opt); 274 | 275 | NLOPT_EXTERN(nlopt_result) nlopt_force_stop(nlopt_opt opt); 276 | NLOPT_EXTERN(nlopt_result) nlopt_set_force_stop(nlopt_opt opt, int val); 277 | NLOPT_EXTERN(int) nlopt_get_force_stop(const nlopt_opt opt); 278 | 279 | /* more algorithm-specific parameters */ 280 | 281 | NLOPT_EXTERN(nlopt_result) nlopt_set_local_optimizer(nlopt_opt opt, const nlopt_opt local_opt); 282 | 283 | NLOPT_EXTERN(nlopt_result) nlopt_set_population(nlopt_opt opt, unsigned pop); 284 | NLOPT_EXTERN(unsigned) nlopt_get_population(const nlopt_opt opt); 285 | 286 | NLOPT_EXTERN(nlopt_result) nlopt_set_vector_storage(nlopt_opt opt, unsigned dim); 287 | NLOPT_EXTERN(unsigned) nlopt_get_vector_storage(const nlopt_opt opt); 288 | 289 | NLOPT_EXTERN(nlopt_result) nlopt_set_default_initial_step(nlopt_opt opt, const double *x); 290 | NLOPT_EXTERN(nlopt_result) nlopt_set_initial_step(nlopt_opt opt, const double *dx); 291 | NLOPT_EXTERN(nlopt_result) nlopt_set_initial_step1(nlopt_opt opt, double dx); 292 | NLOPT_EXTERN(nlopt_result) nlopt_get_initial_step(const nlopt_opt opt, const double *x, double *dx); 293 | 294 | /* the following are functions mainly designed to be used internally 295 | by the Fortran and SWIG wrappers, allow us to tel nlopt_destroy and 296 | nlopt_copy to do something to the f_data pointers (e.g. free or 297 | duplicate them, respectively) */ 298 | typedef void *(*nlopt_munge) (void *p); 299 | NLOPT_EXTERN(void) nlopt_set_munge(nlopt_opt opt, nlopt_munge munge_on_destroy, nlopt_munge munge_on_copy); 300 | typedef void *(*nlopt_munge2) (void *p, void *data); 301 | NLOPT_EXTERN(void) nlopt_munge_data(nlopt_opt opt, nlopt_munge2 munge, void *data); 302 | 303 | /*************************** DEPRECATED API **************************/ 304 | /* The new "object-oriented" API is preferred, since it allows us to 305 | gracefully add new features and algorithm-specific options in a 306 | re-entrant way, and we can automatically assume reasonable defaults 307 | for unspecified parameters. */ 308 | 309 | /* Where possible (e.g. for gcc >= 3.1), enable a compiler warning 310 | for code that uses a deprecated function */ 311 | #if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__==3 && __GNUC_MINOR__ > 0)) 312 | # define NLOPT_DEPRECATED __attribute__((deprecated)) 313 | #else 314 | # define NLOPT_DEPRECATED 315 | #endif 316 | 317 | typedef double (*nlopt_func_old) (int n, const double *x, double *gradient, /* NULL if not needed */ 318 | void *func_data); 319 | 320 | NLOPT_EXTERN(nlopt_result) nlopt_minimize(nlopt_algorithm algorithm, int n, nlopt_func_old f, void *f_data, 321 | const double *lb, const double *ub, /* bounds */ 322 | double *x, /* in: initial guess, out: minimizer */ 323 | double *minf, /* out: minimum */ 324 | double minf_max, double ftol_rel, double ftol_abs, double xtol_rel, const double *xtol_abs, int maxeval, double maxtime) NLOPT_DEPRECATED; 325 | 326 | NLOPT_EXTERN(nlopt_result) nlopt_minimize_constrained(nlopt_algorithm algorithm, int n, nlopt_func_old f, void *f_data, int m, nlopt_func_old fc, void *fc_data, ptrdiff_t fc_datum_size, 327 | const double *lb, const double *ub, /* bounds */ 328 | double *x, /* in: initial guess, out: minimizer */ 329 | double *minf, /* out: minimum */ 330 | double minf_max, double ftol_rel, double ftol_abs, double xtol_rel, const double *xtol_abs, int maxeval, double maxtime) NLOPT_DEPRECATED; 331 | 332 | NLOPT_EXTERN(nlopt_result) nlopt_minimize_econstrained(nlopt_algorithm algorithm, int n, nlopt_func_old f, void *f_data, int m, nlopt_func_old fc, void *fc_data, ptrdiff_t fc_datum_size, int p, nlopt_func_old h, void *h_data, ptrdiff_t h_datum_size, 333 | const double *lb, const double *ub, /* bounds */ 334 | double *x, /* in: initial guess, out: minimizer */ 335 | double *minf, /* out: minimum */ 336 | double minf_max, double ftol_rel, double ftol_abs, 337 | double xtol_rel, const double *xtol_abs, double htol_rel, double htol_abs, int maxeval, double maxtime) NLOPT_DEPRECATED; 338 | 339 | NLOPT_EXTERN(void) nlopt_get_local_search_algorithm(nlopt_algorithm * deriv, nlopt_algorithm * nonderiv, int *maxeval) NLOPT_DEPRECATED; 340 | NLOPT_EXTERN(void) nlopt_set_local_search_algorithm(nlopt_algorithm deriv, nlopt_algorithm nonderiv, int maxeval) NLOPT_DEPRECATED; 341 | 342 | NLOPT_EXTERN(int) nlopt_get_stochastic_population(void) NLOPT_DEPRECATED; 343 | NLOPT_EXTERN(void) nlopt_set_stochastic_population(int pop) NLOPT_DEPRECATED; 344 | 345 | /*********************************************************************/ 346 | 347 | #ifdef __cplusplus 348 | } /* extern "C" */ 349 | #endif /* __cplusplus */ 350 | #endif 351 | -------------------------------------------------------------------------------- /cobyla/nlopt/nlopt_config.h: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | # NLOPT CMake configuration file 3 | # 4 | # NLopt is a free/open-source library for nonlinear optimization, providing 5 | # a common interface for a number of different free optimization routines 6 | # available online as well as original implementations of various other 7 | # algorithms 8 | # WEBSITE: http://ab-initio.mit.edu/wiki/index.php/NLopt 9 | # AUTHOR: Steven G. Johnson 10 | # 11 | # This config.cmake.h.in file was created to compile NLOPT with the CMAKE utility. 12 | # Benoit Scherrer, 2010 CRL, Harvard Medical School 13 | # Copyright (c) 2008-2009 Children's Hospital Boston 14 | # 15 | # Minor changes to the source was applied to make possible the compilation with 16 | # Cmake under Linux/Win32 17 | #============================================================================*/ 18 | 19 | /* Bugfix version number. */ 20 | #define BUGFIX_VERSION 21 | 22 | /* Define to enable extra debugging code. */ 23 | #undef DEBUG 24 | 25 | /* Define to 1 if you have the `BSDgettimeofday' function. */ 26 | #undef HAVE_BSDGETTIMEOFDAY 27 | 28 | /* Define if the copysign function/macro is available. */ 29 | #define HAVE_COPYSIGN 30 | 31 | /* Define if the fpclassify() function/macro is available. */ 32 | /* #undef HAVE_FPCLASSIFY */ 33 | 34 | /* Define to 1 if you have the header file. */ 35 | #define HAVE_GETOPT_H 36 | 37 | /* Define to 1 if you have the getopt function in your standard library. */ 38 | #define HAVE_GETOPT 39 | 40 | /* Define to 1 if you have the `getpid' function. */ 41 | #define HAVE_GETPID 42 | 43 | /* Define if syscall(SYS_gettid) available. */ 44 | #undef HAVE_GETTID_SYSCALL 45 | 46 | /* Define to 1 if you have the `gettimeofday' function. */ 47 | #define HAVE_GETTIMEOFDAY 48 | 49 | /* Define if the isinf() function/macro is available. */ 50 | #define HAVE_ISINF 51 | 52 | /* Define if the isnan() function/macro is available. */ 53 | #define HAVE_ISNAN 54 | 55 | /* Define to 1 if you have the `m' library (-lm). */ 56 | #undef HAVE_LIBM 57 | 58 | /* Define to 1 if you have the `qsort_r' function. */ 59 | #define HAVE_QSORT_R 60 | 61 | /* Define to 1 if you have the header file. */ 62 | #define HAVE_STDINT_H 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #define HAVE_SYS_TIME_H 66 | 67 | /* Define to 1 if you have the `time' function. */ 68 | #define HAVE_TIME 69 | 70 | /* Define to 1 if the system has the type `uint32_t'. */ 71 | #define HAVE_UINT32_T 72 | 73 | /* Define to 1 if you have the header file. */ 74 | #define HAVE_UNISTD_H 75 | 76 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 77 | */ 78 | #undef LT_OBJDIR 79 | 80 | /* Major version number. */ 81 | #define MAJOR_VERSION 82 | 83 | /* Minor version number. */ 84 | #define MINOR_VERSION 85 | 86 | /* Name of package */ 87 | #undef PACKAGE 88 | 89 | /* Define to the address where bug reports for this package should be sent. */ 90 | #undef PACKAGE_BUGREPORT 91 | 92 | /* Define to the full name of this package. */ 93 | #undef PACKAGE_NAME 94 | 95 | /* Define to the full name and version of this package. */ 96 | #undef PACKAGE_STRING 97 | 98 | /* Define to the one symbol short name of this package. */ 99 | #undef PACKAGE_TARNAME 100 | 101 | /* Define to the home page for this package. */ 102 | #undef PACKAGE_URL 103 | 104 | /* Define to the version of this package. */ 105 | #undef PACKAGE_VERSION 106 | 107 | /* replacement for broken HUGE_VAL macro, if needed */ 108 | #undef REPLACEMENT_HUGE_VAL 109 | 110 | /* The size of `unsigned int', as computed by sizeof. */ 111 | #define SIZEOF_UNSIGNED_INT 4 112 | 113 | /* The size of `unsigned long', as computed by sizeof. */ 114 | #define SIZEOF_UNSIGNED_LONG 8 115 | 116 | /* Define to 1 if you have the ANSI C header files. */ 117 | #undef STDC_HEADERS 118 | 119 | /* Define to C thread-local keyword, or to nothing if this is not supported in 120 | your compiler. */ 121 | #define THREADLOCAL 122 | 123 | /* Define to 1 if you can safely include both and . */ 124 | #define TIME_WITH_SYS_TIME 125 | 126 | /* Version number of package */ 127 | #undef VERSION 128 | 129 | /* Define if compiled including C++-based routines */ 130 | /* #undef NLOPT_CXX */ 131 | 132 | /* Define to empty if `const' does not conform to ANSI C. */ 133 | #undef const 134 | 135 | /* Define to `__inline__' or `__inline' if that's what the C compiler 136 | calls it, or to nothing if 'inline' is not supported under any name. */ 137 | #ifndef __cplusplus 138 | #undef inline 139 | #endif 140 | -------------------------------------------------------------------------------- /cobyla/nlopt/nlopt_config.h.in: -------------------------------------------------------------------------------- 1 | /*============================================================================== 2 | # NLOPT CMake configuration file 3 | # 4 | # NLopt is a free/open-source library for nonlinear optimization, providing 5 | # a common interface for a number of different free optimization routines 6 | # available online as well as original implementations of various other 7 | # algorithms 8 | # WEBSITE: http://ab-initio.mit.edu/wiki/index.php/NLopt 9 | # AUTHOR: Steven G. Johnson 10 | # 11 | # This config.cmake.h.in file was created to compile NLOPT with the CMAKE utility. 12 | # Benoit Scherrer, 2010 CRL, Harvard Medical School 13 | # Copyright (c) 2008-2009 Children's Hospital Boston 14 | # 15 | # Minor changes to the source was applied to make possible the compilation with 16 | # Cmake under Linux/Win32 17 | #============================================================================*/ 18 | 19 | /* Bugfix version number. */ 20 | #define BUGFIX_VERSION @NLOPT_BUGFIX_VERSION@ 21 | 22 | /* Define to enable extra debugging code. */ 23 | #undef DEBUG 24 | 25 | /* Define to 1 if you have the `BSDgettimeofday' function. */ 26 | #undef HAVE_BSDGETTIMEOFDAY 27 | 28 | /* Define if the copysign function/macro is available. */ 29 | #cmakedefine HAVE_COPYSIGN 30 | 31 | /* Define if the fpclassify() function/macro is available. */ 32 | #cmakedefine HAVE_FPCLASSIFY 33 | 34 | /* Define to 1 if you have the header file. */ 35 | #cmakedefine HAVE_GETOPT_H 36 | 37 | /* Define to 1 if you have the getopt function in your standard library. */ 38 | #cmakedefine HAVE_GETOPT 39 | 40 | /* Define to 1 if you have the `getpid' function. */ 41 | #cmakedefine HAVE_GETPID 42 | 43 | /* Define if syscall(SYS_gettid) available. */ 44 | #undef HAVE_GETTID_SYSCALL 45 | 46 | /* Define to 1 if you have the `gettimeofday' function. */ 47 | #cmakedefine HAVE_GETTIMEOFDAY 48 | 49 | /* Define if the isinf() function/macro is available. */ 50 | #cmakedefine HAVE_ISINF 51 | 52 | /* Define if the isnan() function/macro is available. */ 53 | #cmakedefine HAVE_ISNAN 54 | 55 | /* Define to 1 if you have the `m' library (-lm). */ 56 | #undef HAVE_LIBM 57 | 58 | /* Define to 1 if you have the `qsort_r' function. */ 59 | #cmakedefine HAVE_QSORT_R 60 | 61 | /* Define to 1 if you have the header file. */ 62 | #cmakedefine HAVE_STDINT_H 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #cmakedefine HAVE_SYS_TIME_H 66 | 67 | /* Define to 1 if you have the `time' function. */ 68 | #cmakedefine HAVE_TIME 69 | 70 | /* Define to 1 if the system has the type `uint32_t'. */ 71 | #cmakedefine HAVE_UINT32_T 72 | 73 | /* Define to 1 if you have the header file. */ 74 | #cmakedefine HAVE_UNISTD_H 75 | 76 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 77 | */ 78 | #undef LT_OBJDIR 79 | 80 | /* Major version number. */ 81 | #define MAJOR_VERSION @NLOPT_MAJOR_VERSION@ 82 | 83 | /* Minor version number. */ 84 | #define MINOR_VERSION @NLOPT_MINOR_VERSION@ 85 | 86 | /* Name of package */ 87 | #undef PACKAGE 88 | 89 | /* Define to the address where bug reports for this package should be sent. */ 90 | #undef PACKAGE_BUGREPORT 91 | 92 | /* Define to the full name of this package. */ 93 | #undef PACKAGE_NAME 94 | 95 | /* Define to the full name and version of this package. */ 96 | #undef PACKAGE_STRING 97 | 98 | /* Define to the one symbol short name of this package. */ 99 | #undef PACKAGE_TARNAME 100 | 101 | /* Define to the home page for this package. */ 102 | #undef PACKAGE_URL 103 | 104 | /* Define to the version of this package. */ 105 | #undef PACKAGE_VERSION 106 | 107 | /* replacement for broken HUGE_VAL macro, if needed */ 108 | #undef REPLACEMENT_HUGE_VAL 109 | 110 | /* The size of `unsigned int', as computed by sizeof. */ 111 | #define SIZEOF_UNSIGNED_INT @SIZEOF_UNSIGNED_INT@ 112 | 113 | /* The size of `unsigned long', as computed by sizeof. */ 114 | #define SIZEOF_UNSIGNED_LONG @SIZEOF_UNSIGNED_LONG@ 115 | 116 | /* Define to 1 if you have the ANSI C header files. */ 117 | #undef STDC_HEADERS 118 | 119 | /* Define to C thread-local keyword, or to nothing if this is not supported in 120 | your compiler. */ 121 | #define THREADLOCAL @THREADLOCAL@ 122 | 123 | /* Define to 1 if you can safely include both and . */ 124 | #cmakedefine TIME_WITH_SYS_TIME 125 | 126 | /* Version number of package */ 127 | #undef VERSION 128 | 129 | /* Define if compiled including C++-based routines */ 130 | #cmakedefine NLOPT_CXX 131 | 132 | /* Define to empty if `const' does not conform to ANSI C. */ 133 | #undef const 134 | 135 | /* Define to `__inline__' or `__inline' if that's what the C compiler 136 | calls it, or to nothing if 'inline' is not supported under any name. */ 137 | #ifndef __cplusplus 138 | #undef inline 139 | #endif 140 | -------------------------------------------------------------------------------- /cobyla/nlopt/rescale.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2014 Massachusetts Institute of Technology 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining 4 | * a copy of this software and associated documentation files (the 5 | * "Software"), to deal in the Software without restriction, including 6 | * without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to 9 | * the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "nlopt-util.h" 25 | 26 | /* Return a new array of length n (> 0) that gives a rescaling factor 27 | for each dimension, or NULL if out of memory, with dx being the 28 | array of nonzero initial steps in each dimension. */ 29 | double *nlopt_compute_rescaling(unsigned n, const double *dx) 30 | { 31 | double *s = (double *) malloc(sizeof(double) * n); 32 | unsigned i; 33 | 34 | if (!s) 35 | return NULL; 36 | for (i = 0; i < n; ++i) 37 | s[i] = 1.0; /* default: no rescaling */ 38 | if (n == 1) 39 | return s; 40 | 41 | for (i = 1; i < n && dx[i] == dx[i - 1]; ++i); 42 | if (i < n) { /* unequal initial steps, rescale to make equal to dx[0] */ 43 | for (i = 1; i < n; ++i) 44 | s[i] = dx[i] / dx[0]; 45 | } 46 | return s; 47 | } 48 | 49 | void nlopt_rescale(unsigned n, const double *s, const double *x, double *xs) 50 | { 51 | unsigned i; 52 | if (!s) { 53 | for (i = 0; i < n; ++i) 54 | xs[i] = x[i]; 55 | } else { 56 | for (i = 0; i < n; ++i) 57 | xs[i] = x[i] / s[i]; 58 | } 59 | } 60 | 61 | void nlopt_unscale(unsigned n, const double *s, const double *x, double *xs) 62 | { 63 | unsigned i; 64 | if (!s) { 65 | for (i = 0; i < n; ++i) 66 | xs[i] = x[i]; 67 | } else { 68 | for (i = 0; i < n; ++i) 69 | xs[i] = x[i] * s[i]; 70 | } 71 | } 72 | 73 | /* return a new array of length n equal to the original array 74 | x divided by the scale factors s, or NULL on a memory error */ 75 | double *nlopt_new_rescaled(unsigned n, const double *s, const double *x) 76 | { 77 | double *xs = (double *) malloc(sizeof(double) * n); 78 | if (!xs) 79 | return NULL; 80 | nlopt_rescale(n, s, x, xs); 81 | return xs; 82 | } 83 | 84 | /* since rescaling can flip the signs of the x components and the bounds, 85 | we may have to re-order the bounds in order to ensure that they 86 | remain in the correct order */ 87 | void nlopt_reorder_bounds(unsigned n, double *lb, double *ub) 88 | { 89 | unsigned i; 90 | for (i = 0; i < n; ++i) 91 | if (lb[i] > ub[i]) { 92 | double t = lb[i]; 93 | lb[i] = ub[i]; 94 | ub[i] = t; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /cobyla/nlopt/stop.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2014 Massachusetts Institute of Technology 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining 4 | * a copy of this software and associated documentation files (the 5 | * "Software"), to deal in the Software without restriction, including 6 | * without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to 9 | * the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "nlopt-util.h" 29 | 30 | /* utility routines to implement the various stopping criteria */ 31 | 32 | static double sc(double x, double smin, double smax) 33 | { 34 | return smin + x * (smax - smin); 35 | } 36 | 37 | static double vector_norm(unsigned n, const double *vec, const double *w, const double *scale_min, const double *scale_max) 38 | { 39 | unsigned i; 40 | double ret = 0; 41 | if (scale_min && scale_max) { 42 | if (w) 43 | for (i = 0; i < n; i++) 44 | ret += w[i] * fabs(sc(vec[i], scale_min[i], scale_max[i])); 45 | else 46 | for (i = 0; i < n; i++) 47 | ret += fabs(sc(vec[i], scale_min[i], scale_max[i])); 48 | } else { 49 | if (w) 50 | for (i = 0; i < n; i++) 51 | ret += w[i] * fabs(vec[i]); 52 | else 53 | for (i = 0; i < n; i++) 54 | ret += fabs(vec[i]); 55 | } 56 | return ret; 57 | } 58 | 59 | static double diff_norm(unsigned n, const double *x, const double *oldx, const double *w, const double *scale_min, const double *scale_max) 60 | { 61 | unsigned i; 62 | double ret = 0; 63 | if (scale_min && scale_max) { 64 | if (w) 65 | for (i = 0; i < n; i++) 66 | ret += w[i] * fabs(sc(x[i], scale_min[i], scale_max[i]) - sc(oldx[i], scale_min[i], scale_max[i])); 67 | else 68 | for (i = 0; i < n; i++) 69 | ret += fabs(sc(x[i], scale_min[i], scale_max[i]) - sc(oldx[i], scale_min[i], scale_max[i])); 70 | } else { 71 | if (w) 72 | for (i = 0; i < n; i++) 73 | ret += w[i] * fabs(x[i] - oldx[i]); 74 | else 75 | for (i = 0; i < n; i++) 76 | ret += fabs(x[i] - oldx[i]); 77 | } 78 | return ret; 79 | } 80 | 81 | static int relstop(double vold, double vnew, double reltol, double abstol) 82 | { 83 | if (nlopt_isinf(vold)) 84 | return 0; 85 | return (fabs(vnew - vold) < abstol || fabs(vnew - vold) < reltol * (fabs(vnew) + fabs(vold)) * 0.5 || (reltol > 0 && vnew == vold)); /* catch vnew == vold == 0 */ 86 | } 87 | 88 | int nlopt_stop_ftol(const nlopt_stopping * s, double f, double oldf) 89 | { 90 | return (relstop(oldf, f, s->ftol_rel, s->ftol_abs)); 91 | } 92 | 93 | int nlopt_stop_f(const nlopt_stopping * s, double f, double oldf) 94 | { 95 | return (f <= s->minf_max || nlopt_stop_ftol(s, f, oldf)); 96 | } 97 | 98 | int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) 99 | { 100 | unsigned i; 101 | if (diff_norm(s->n, x, oldx, s->x_weights, NULL, NULL) < s->xtol_rel * vector_norm(s->n, x, s->x_weights, NULL, NULL)) 102 | return 1; 103 | if (!s->xtol_abs) return 0; 104 | for (i = 0; i < s->n; ++i) 105 | if (fabs(x[i] - oldx[i]) >= s->xtol_abs[i]) 106 | return 0; 107 | return 1; 108 | } 109 | 110 | int nlopt_stop_dx(const nlopt_stopping * s, const double *x, const double *dx) 111 | { 112 | unsigned i; 113 | if (vector_norm(s->n, dx, s->x_weights, NULL, NULL) < s->xtol_rel * vector_norm(s->n, x, s->x_weights, NULL, NULL)) 114 | return 1; 115 | if (!s->xtol_abs) return 0; 116 | for (i = 0; i < s->n; ++i) 117 | if (fabs(dx[i]) >= s->xtol_abs[i]) 118 | return 0; 119 | return 1; 120 | } 121 | 122 | /* some of the algorithms rescale x to a unit hypercube, so we need to 123 | scale back before we can compare to the tolerances */ 124 | int nlopt_stop_xs(const nlopt_stopping * s, const double *xs, const double *oldxs, const double *scale_min, const double *scale_max) 125 | { 126 | unsigned i; 127 | if (diff_norm(s->n, xs, oldxs, s->x_weights, scale_min, scale_max) < s->xtol_rel * vector_norm(s->n, xs, s->x_weights, scale_min, scale_max)) 128 | return 1; 129 | if (!s->xtol_abs) return 0; 130 | for (i = 0; i < s->n; ++i) 131 | if (fabs(sc(xs[i], scale_min[i], scale_max[i]) - sc(oldxs[i], scale_min[i], scale_max[i])) >= s->xtol_abs[i]) 132 | return 0; 133 | return 1; 134 | } 135 | 136 | int nlopt_stop_evals(const nlopt_stopping * s) 137 | { 138 | return (s->maxeval > 0 && *(s->nevals_p) >= s->maxeval); 139 | } 140 | 141 | int nlopt_stop_time_(double start, double maxtime) 142 | { 143 | return (maxtime > 0 && nlopt_seconds() - start >= maxtime); 144 | } 145 | 146 | int nlopt_stop_time(const nlopt_stopping * s) 147 | { 148 | return nlopt_stop_time_(s->start, s->maxtime); 149 | } 150 | 151 | int nlopt_stop_evalstime(const nlopt_stopping * stop) 152 | { 153 | return nlopt_stop_evals(stop) || nlopt_stop_time(stop); 154 | } 155 | 156 | int nlopt_stop_forced(const nlopt_stopping * stop) 157 | { 158 | return stop->force_stop && *(stop->force_stop); 159 | } 160 | 161 | unsigned nlopt_count_constraints(unsigned p, const nlopt_constraint * c) 162 | { 163 | unsigned i, count = 0; 164 | for (i = 0; i < p; ++i) 165 | count += c[i].m; 166 | return count; 167 | } 168 | 169 | unsigned nlopt_max_constraint_dim(unsigned p, const nlopt_constraint * c) 170 | { 171 | unsigned i, max_dim = 0; 172 | for (i = 0; i < p; ++i) 173 | if (c[i].m > max_dim) 174 | max_dim = c[i].m; 175 | return max_dim; 176 | } 177 | 178 | void nlopt_eval_constraint(double *result, double *grad, const nlopt_constraint * c, unsigned n, const double *x) 179 | { 180 | if (c->f) 181 | result[0] = c->f(n, x, grad, c->f_data); 182 | else 183 | c->mf(c->m, result, n, x, grad, c->f_data); 184 | } 185 | 186 | char *nlopt_vsprintf(char *p, const char *format, va_list ap) 187 | { 188 | size_t len = strlen(format) + 128; 189 | int ret; 190 | 191 | p = (char *) realloc(p, len); 192 | if (!p) 193 | abort(); 194 | 195 | /* TODO: check HAVE_VSNPRINTF, and fallback to vsprintf otherwise */ 196 | while ((ret = vsnprintf(p, len, format, ap)) < 0 || (size_t) ret >= len) { 197 | /* C99 vsnprintf returns the required number of bytes (excluding \0) 198 | if the buffer is too small; older versions (e.g. MS) return -1 */ 199 | len = ret >= 0 ? (size_t) (ret + 1) : (len * 3) >> 1; 200 | p = (char *) realloc(p, len); 201 | if (!p) 202 | abort(); 203 | } 204 | return p; 205 | } 206 | 207 | void nlopt_stop_msg(const nlopt_stopping * s, const char *format, ...) 208 | { 209 | va_list ap; 210 | if (s->stop_msg) { 211 | va_start(ap, format); 212 | *(s->stop_msg) = nlopt_vsprintf(*(s->stop_msg), format, ap); 213 | va_end(ap); 214 | } 215 | } 216 | 217 | /*************************************************************************/ 218 | 219 | int nlopt_isinf(double x) 220 | { 221 | return (fabs(x) >= HUGE_VAL * 0.99) 222 | #if defined(HAVE_ISINF) 223 | || isinf(x) 224 | #else 225 | || (!nlopt_isnan(x) && nlopt_isnan(x - x)) 226 | #endif 227 | ; 228 | } 229 | 230 | int nlopt_isfinite(double x) 231 | { 232 | return (fabs(x) <= DBL_MAX) 233 | #if defined(HAVE_ISFINITE) 234 | || isfinite(x) 235 | #elif defined(_WIN32) 236 | || _finite(x) 237 | #endif 238 | ; 239 | } 240 | 241 | int nlopt_istiny(double x) 242 | { 243 | if (x == 0.0) 244 | return 1; 245 | else { 246 | #if defined(HAVE_FPCLASSIFY) 247 | return fpclassify(x) == FP_SUBNORMAL; 248 | #elif defined(_WIN32) 249 | int c = _fpclass(x); 250 | return c == _FPCLASS_ND || c == _FPCLASS_PD; 251 | #else 252 | return fabs(x) < 2.2250738585072014e-308; /* assume IEEE 754 double */ 253 | #endif 254 | } 255 | } 256 | 257 | int nlopt_isnan(double x) 258 | { 259 | #if defined(HAVE_ISNAN) 260 | return isnan(x); 261 | #elif defined(_WIN32) 262 | return _isnan(x); 263 | #else 264 | return (x != x); /* might fail with aggressive optimization */ 265 | #endif 266 | } 267 | -------------------------------------------------------------------------------- /cobyla/nlopt/timer.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2014 Massachusetts Institute of Technology 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining 4 | * a copy of this software and associated documentation files (the 5 | * "Software"), to deal in the Software without restriction, including 6 | * without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to 8 | * permit persons to whom the Software is furnished to do so, subject to 9 | * the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be 12 | * included in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include "nlopt-util.h" 24 | 25 | #ifdef TIME_WITH_SYS_TIME 26 | # include 27 | # include 28 | #else 29 | # ifdef HAVE_SYS_TIME_H 30 | # include 31 | # else 32 | # include 33 | # endif 34 | #endif 35 | 36 | #if defined(_WIN32) || defined(__WIN32__) 37 | # include 38 | #endif 39 | 40 | /* return time in seconds since some arbitrary point in the past */ 41 | double nlopt_seconds(void) 42 | { 43 | static THREADLOCAL int start_inited = 0; /* whether start time has been initialized */ 44 | #if defined(HAVE_GETTIMEOFDAY) 45 | static THREADLOCAL struct timeval start; 46 | struct timeval tv; 47 | if (!start_inited) { 48 | start_inited = 1; 49 | gettimeofday(&start, NULL); 50 | } 51 | gettimeofday(&tv, NULL); 52 | return (tv.tv_sec - start.tv_sec) + 1.e-6 * (tv.tv_usec - start.tv_usec); 53 | #elif defined(HAVE_TIME) 54 | return time(NULL); 55 | #elif defined(_WIN32) || defined(__WIN32__) 56 | static THREADLOCAL ULONGLONG start; 57 | FILETIME ft; 58 | if (!start_inited) { 59 | start_inited = 1; 60 | GetSystemTimeAsFileTime(&ft); 61 | start = (((ULONGLONG) ft.dwHighDateTime) << 32) + ft.dwLowDateTime; 62 | } 63 | GetSystemTimeAsFileTime(&ft); 64 | return 100e-9 * (((((ULONGLONG) ft.dwHighDateTime) << 32) + ft.dwLowDateTime) - start); 65 | #else 66 | /* use clock() as a fallback... this is somewhat annoying 67 | because clock() may wrap around with a fairly short period */ 68 | static THREADLOCAL clock_t start; 69 | if (!start_inited) { 70 | start_inited = 1; 71 | start = clock(); 72 | } 73 | return (clock() - start) * 1.0 / CLOCKS_PER_SEC; 74 | #endif 75 | } 76 | 77 | /* number based on time for use as random seed */ 78 | unsigned long nlopt_time_seed(void) 79 | { 80 | #if defined(HAVE_GETTIMEOFDAY) 81 | struct timeval tv; 82 | gettimeofday(&tv, NULL); 83 | return (tv.tv_sec ^ tv.tv_usec); 84 | #elif defined(HAVE_TIME) 85 | return time(NULL); 86 | #elif defined(_WIN32) || defined(__WIN32__) 87 | FILETIME ft; 88 | GetSystemTimeAsFileTime(&ft); 89 | return ft.dwHighDateTime ^ ft.dwLowDateTime; 90 | #else 91 | return clock(); 92 | #endif 93 | } 94 | -------------------------------------------------------------------------------- /examples/paraboloid.rs: -------------------------------------------------------------------------------- 1 | use argmin::core::observers::ObserverMode; 2 | use argmin::core::{CostFunction, Error, Executor}; 3 | use argmin_observer_slog::SlogLogger; 4 | use cobyla::{minimize, CobylaSolver, Func, RhoBeg, StopTols}; 5 | 6 | /// Problem cost function 7 | fn paraboloid(x: &[f64], _data: &mut ()) -> f64 { 8 | 10. * (x[0] + 1.).powf(2.) + x[1].powf(2.) 9 | } 10 | 11 | /// Problem Definition: minimize paraboloid(x) subject to x0 >= 0 12 | struct ParaboloidProblem; 13 | impl CostFunction for ParaboloidProblem { 14 | type Param = Vec; 15 | type Output = Vec; 16 | 17 | fn cost(&self, x: &Self::Param) -> Result { 18 | let fx = paraboloid(x, &mut ()); 19 | Ok(vec![fx, x[0]]) 20 | } 21 | } 22 | 23 | fn main() { 24 | println!("*** Solve paraboloid problem using nlopt_cobyla"); 25 | 26 | // Initial guess 27 | let xinit = vec![1., 1.]; 28 | 29 | // Define a constraint: x0 > 0 30 | let mut cons: Vec<&dyn Func<()>> = vec![]; 31 | let cstr1 = |x: &[f64], _u: &mut ()| x[0]; 32 | cons.push(&cstr1); 33 | 34 | // Define a stopping criterion on objective function change 35 | let stop_tol = StopTols { 36 | ftol_rel: 1e-4, 37 | ..StopTols::default() 38 | }; 39 | 40 | match minimize( 41 | paraboloid, 42 | &xinit, 43 | &[(-10., 10.), (-10., 10.)], 44 | &cons, 45 | (), 46 | 200, 47 | RhoBeg::All(0.5), 48 | Some(stop_tol), 49 | ) { 50 | Ok((status, x_opt, y_opt)) => { 51 | println!("status = {:?}", status); 52 | println!("x_opt = {:?}", x_opt); 53 | println!("y_opt = {}", y_opt); 54 | } 55 | Err((e, _, _)) => println!("Optim error: {:?}", e), 56 | } 57 | 58 | println!( 59 | "*** Solve paraboloid problem using Cobyla argmin solver implemented on top of fmin_cobyla impl" 60 | ); 61 | let problem = ParaboloidProblem; 62 | let solver = CobylaSolver::new(vec![1., 1.]); 63 | 64 | let res = Executor::new(problem, solver) 65 | .configure(|state| state.max_iters(100).iprint(0)) 66 | .add_observer(SlogLogger::term(), ObserverMode::Always) 67 | .run() 68 | .unwrap(); 69 | 70 | // Wait a second (lets the logger flush everything before printing again) 71 | std::thread::sleep(std::time::Duration::from_secs(1)); 72 | println!("*** Result argmin solver impl ***"); 73 | println!("Result:\n{}", res); 74 | } 75 | -------------------------------------------------------------------------------- /src/cobyla_solver.rs: -------------------------------------------------------------------------------- 1 | use crate::cobyla::{ 2 | cobyla_context_t, cobyla_create, cobyla_delete, cobyla_get_status, cobyla_iterate, 3 | cobyla_reason, CobylaStatus, 4 | }; 5 | use crate::cobyla_state::*; 6 | use std::mem::ManuallyDrop; 7 | 8 | use argmin::core::{CostFunction, Problem, Solver, State, TerminationStatus, KV}; 9 | #[cfg(feature = "serde1")] 10 | use serde::{Deserialize, Serialize}; 11 | 12 | /// [Argmin Solver](https://www.argmin-rs.org/book/index.html) which implements COBYLA method. 13 | /// 14 | /// ``` 15 | /// use argmin::core::{CostFunction, Error, Executor}; 16 | /// use argmin::core::observers::{ObserverMode}; 17 | /// use argmin_observer_slog::SlogLogger; 18 | /// use cobyla::CobylaSolver; 19 | /// 20 | /// struct ParaboloidProblem; 21 | /// impl CostFunction for ParaboloidProblem { 22 | /// type Param = Vec; 23 | /// type Output = Vec; 24 | /// 25 | /// // Minimize 10*(x0+1)^2 + x1^2 subject to x0 >= 0 26 | /// fn cost(&self, x: &Self::Param) -> Result { 27 | /// Ok(vec![10. * (x[0] + 1.).powf(2.) + x[1].powf(2.), x[0]]) 28 | /// } 29 | /// } 30 | /// 31 | /// let pb = ParaboloidProblem; 32 | /// let solver = CobylaSolver::new(vec![1., 1.]); 33 | /// 34 | /// let res = Executor::new(pb, solver) 35 | /// .configure(|state| state.max_iters(100)) 36 | /// .add_observer(SlogLogger::term(), ObserverMode::Always) 37 | /// .run() 38 | /// .unwrap(); 39 | /// 40 | /// // Wait a second (lets the logger flush everything before printing again) 41 | /// std::thread::sleep(std::time::Duration::from_secs(1)); 42 | /// 43 | /// println!("Result of COBYLA:\n{}", res); 44 | /// ``` 45 | #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] 46 | pub struct CobylaSolver { 47 | /// Initial guess for x value 48 | x0: Vec, 49 | } 50 | 51 | impl CobylaSolver { 52 | pub fn new(x0: Vec) -> Self { 53 | CobylaSolver { x0 } 54 | } 55 | } 56 | 57 | impl Solver for CobylaSolver 58 | where 59 | O: CostFunction, Output = Vec>, 60 | { 61 | fn name(&self) -> &str { 62 | "COBYLA" 63 | } 64 | 65 | /// Initializes the algorithm. 66 | /// 67 | /// Executed before any iterations are performed and has access to the optimization problem 68 | /// definition and the internal state of the solver. 69 | /// Returns an updated `state` and optionally a `KV` which holds key-value pairs used in 70 | /// [Observers](`argmin::core::observers::Observe`). 71 | /// The default implementation returns the unaltered `state` and no `KV`. 72 | #[allow(clippy::useless_conversion)] 73 | fn init( 74 | &mut self, 75 | problem: &mut Problem, 76 | state: CobylaState, 77 | ) -> std::result::Result<(CobylaState, Option), argmin::core::Error> { 78 | let n = self.x0.len() as i32; 79 | let fx0 = problem.cost(&self.x0)?; 80 | let m = (fx0.len() - 1) as i32; 81 | let rhobeg = state.rhobeg(); 82 | let rhoend = state.get_rhoend(); 83 | let iprint = state.get_iprint(); 84 | let maxfun = state.get_maxfun(); 85 | let mut initial_state = state; 86 | let ptr = unsafe { 87 | cobyla_create( 88 | n.into(), 89 | m.into(), 90 | rhobeg, 91 | rhoend, 92 | iprint.into(), 93 | maxfun.into(), 94 | ) 95 | }; 96 | initial_state.cobyla_context = Some(ManuallyDrop::new(ptr)); 97 | 98 | let initial_state = initial_state.param(self.x0.clone()).cost(fx0); 99 | Ok((initial_state, None)) 100 | } 101 | 102 | /// Computes a single iteration of the algorithm and has access to the optimization problem 103 | /// definition and the internal state of the solver. 104 | /// Returns an updated `state` and optionally a `KV` which holds key-value pairs used in 105 | /// [Observers](`argmin::core::observers::Observe`). 106 | fn next_iter( 107 | &mut self, 108 | problem: &mut Problem, 109 | state: CobylaState, 110 | ) -> std::result::Result<(CobylaState, Option), argmin::core::Error> { 111 | let mut x = state.get_param().unwrap().clone(); 112 | if let Some(ctx) = state.cobyla_context.as_ref() { 113 | let cost = problem.cost(&x)?; 114 | let f = cost[0]; 115 | let mut c = Box::new(cost[1..].to_vec()); 116 | 117 | let _status = unsafe { 118 | cobyla_iterate( 119 | **ctx as *mut cobyla_context_t, 120 | f, 121 | x.as_mut_ptr(), 122 | c.as_mut_ptr(), 123 | ) 124 | }; 125 | let fx = problem.cost(&x)?; 126 | let state = state.param(x).cost(fx); 127 | return Ok((state, None)); 128 | } 129 | 130 | Ok((state, None)) 131 | } 132 | 133 | /// Used to implement stopping criteria, in particular criteria which are not covered by 134 | /// ([`terminate_internal`](`Solver::terminate_internal`). 135 | /// 136 | /// This method has access to the internal state and returns an `TerminationReason`. 137 | fn terminate(&mut self, state: &CobylaState) -> TerminationStatus { 138 | if let Some(ctx) = state.cobyla_context.as_ref() { 139 | let status = unsafe { 140 | let ctx_ptr = **ctx; 141 | cobyla_get_status(ctx_ptr) 142 | }; 143 | if status == CobylaStatus::COBYLA_ITERATE as i32 { 144 | return TerminationStatus::NotTerminated; 145 | } else { 146 | let cstr = unsafe { std::ffi::CStr::from_ptr(cobyla_reason(status)) }; 147 | let reason = cstr.to_str().unwrap().to_string(); 148 | unsafe { cobyla_delete(**ctx as *mut cobyla_context_t) } 149 | if reason == "algorithm was successful" { 150 | return TerminationStatus::Terminated( 151 | argmin::core::TerminationReason::SolverConverged, 152 | ); 153 | } 154 | return TerminationStatus::Terminated(argmin::core::TerminationReason::SolverExit( 155 | reason, 156 | )); 157 | } 158 | } 159 | TerminationStatus::Terminated(argmin::core::TerminationReason::SolverExit( 160 | "Unknown".to_string(), 161 | )) 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/cobyla_state.rs: -------------------------------------------------------------------------------- 1 | use crate::cobyla::cobyla_context_t; 2 | /// Implementation of `argmin::IterState` for Cobyla optimizer 3 | use argmin::core::{Problem, State, TerminationReason, TerminationStatus}; 4 | #[cfg(feature = "serde1")] 5 | use serde::{Deserialize, Serialize}; 6 | use std::collections::HashMap; 7 | use std::mem::ManuallyDrop; 8 | 9 | /// Maintains the state from iteration to iteration of the [crate::CobylaSolver]. 10 | /// 11 | /// This struct is passed from one iteration of an algorithm to the next. 12 | /// 13 | /// Keeps track of 14 | /// 15 | /// * parameter vector of current and previous iteration 16 | /// * best parameter vector of current and previous iteration 17 | /// * cost function value (objective and constraint functions values) of current and previous iteration 18 | /// * current and previous best cost function value 19 | /// * target cost function value 20 | /// * current iteration number 21 | /// * iteration number where the last best parameter vector was found 22 | /// * maximum number of iterations that will be executed 23 | /// * problem function evaluation counts 24 | /// * elapsed time 25 | /// * termination status 26 | /// * COBYLA specific parameters: rhobeg, rhoend, iprint, maxfun 27 | /// 28 | #[derive(Clone, Debug, Default)] 29 | #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] 30 | pub struct CobylaState { 31 | /// Current parameter vector 32 | pub param: Option>, 33 | /// Previous parameter vector 34 | pub prev_param: Option>, 35 | /// Current best parameter vector 36 | pub best_param: Option>, 37 | /// Previous best parameter vector 38 | pub prev_best_param: Option>, 39 | 40 | /// Current cost function value 41 | pub cost: Option>, 42 | /// Previous cost function value 43 | pub prev_cost: Option>, 44 | /// Current best cost function value 45 | pub best_cost: Option>, 46 | /// Previous best cost function value 47 | pub prev_best_cost: Option>, 48 | /// Target cost function value 49 | pub target_cost: f64, 50 | 51 | /// Current iteration 52 | pub iter: u64, 53 | /// Iteration number of last best cost 54 | pub last_best_iter: u64, 55 | /// Maximum number of iterations 56 | pub max_iters: u64, 57 | /// Evaluation counts 58 | pub counts: HashMap, 59 | /// Time required so far 60 | pub time: Option, 61 | /// Status of optimization execution 62 | pub termination_status: TerminationStatus, 63 | 64 | /// Rho start value 65 | pub rhobeg: f64, 66 | /// Rho end value 67 | pub rhoend: f64, 68 | /// Control of traces 69 | pub iprint: i32, 70 | /// Cost function calls budget 71 | pub maxfun: i32, 72 | 73 | #[cfg_attr(feature = "serde1", serde(skip))] 74 | pub cobyla_context: Option>, 75 | } 76 | 77 | impl CobylaState 78 | where 79 | Self: State, 80 | { 81 | /// Set parameter vector. This shifts the stored parameter vector to the previous parameter 82 | /// vector. 83 | /// 84 | /// # Example 85 | /// 86 | /// ``` 87 | /// # use argmin::core::{IterState, State}; 88 | /// # use cobyla::CobylaState; 89 | /// # let state = CobylaState::new(); 90 | /// # let param_old = vec![1.0f64, 2.0f64]; 91 | /// # let state = state.param(param_old); 92 | /// # assert!(state.prev_param.is_none()); 93 | /// # assert_eq!(state.param.as_ref().unwrap()[0].to_ne_bytes(), 1.0f64.to_ne_bytes()); 94 | /// # assert_eq!(state.param.as_ref().unwrap()[1].to_ne_bytes(), 2.0f64.to_ne_bytes()); 95 | /// # let param = vec![0.0f64, 3.0f64]; 96 | /// let state = state.param(param); 97 | /// # assert_eq!(state.prev_param.as_ref().unwrap()[0].to_ne_bytes(), 1.0f64.to_ne_bytes()); 98 | /// # assert_eq!(state.prev_param.as_ref().unwrap()[1].to_ne_bytes(), 2.0f64.to_ne_bytes()); 99 | /// # assert_eq!(state.param.as_ref().unwrap()[0].to_ne_bytes(), 0.0f64.to_ne_bytes()); 100 | /// # assert_eq!(state.param.as_ref().unwrap()[1].to_ne_bytes(), 3.0f64.to_ne_bytes()); 101 | /// ``` 102 | #[must_use] 103 | pub fn param(mut self, param: Vec) -> Self { 104 | std::mem::swap(&mut self.prev_param, &mut self.param); 105 | self.param = Some(param); 106 | self 107 | } 108 | 109 | /// Set target cost. 110 | /// 111 | /// When this cost is reached, the algorithm will stop. The default is 112 | /// `Self::Float::NEG_INFINITY`. 113 | /// 114 | /// # Example 115 | /// 116 | /// ``` 117 | /// # use cobyla::CobylaState; 118 | /// # use argmin::core::{State, ArgminFloat}; 119 | /// # let state: CobylaState = CobylaState::new(); 120 | /// # assert_eq!(state.target_cost.to_ne_bytes(), f64::NEG_INFINITY.to_ne_bytes()); 121 | /// let state = state.target_cost(0.0); 122 | /// # assert_eq!(state.target_cost.to_ne_bytes(), 0.0f64.to_ne_bytes()); 123 | /// ``` 124 | #[must_use] 125 | pub fn target_cost(mut self, target_cost: f64) -> Self { 126 | self.target_cost = target_cost; 127 | self 128 | } 129 | 130 | /// Set maximum number of iterations 131 | /// 132 | /// # Example 133 | /// 134 | /// ``` 135 | /// # use cobyla::CobylaState; 136 | /// # use argmin::core::{State, ArgminFloat}; 137 | /// # let state: CobylaState = CobylaState::new(); 138 | /// # assert_eq!(state.max_iters, std::u64::MAX); 139 | /// let state = state.max_iters(1000); 140 | /// # assert_eq!(state.max_iters, 1000); 141 | /// ``` 142 | #[must_use] 143 | pub fn max_iters(mut self, iters: u64) -> Self { 144 | self.max_iters = iters; 145 | self 146 | } 147 | /// Alias for max_iters using historic cobyla terminology 148 | #[must_use] 149 | pub fn maxfun(mut self, maxfun: u64) -> Self { 150 | self.max_iters = maxfun; 151 | self 152 | } 153 | 154 | /// Set maximum number of iterations 155 | /// 156 | /// # Example 157 | /// 158 | /// ``` 159 | /// # use cobyla::CobylaState; 160 | /// # use argmin::core::{State, ArgminFloat}; 161 | /// # let state: CobylaState = CobylaState::new(); 162 | /// # assert_eq!(state.iprint, 1); 163 | /// let state = state.iprint(0); 164 | /// # assert_eq!(state.iprint, 0); 165 | /// ``` 166 | #[must_use] 167 | pub fn iprint(mut self, iprint: i32) -> Self { 168 | self.iprint = iprint; 169 | self 170 | } 171 | 172 | /// Set the current cost function value. This shifts the stored cost function value to the 173 | /// previous cost function value. 174 | /// 175 | /// # Example 176 | /// 177 | /// ``` 178 | /// # use argmin::core::State; 179 | /// # use cobyla::CobylaState; 180 | /// # let state: CobylaState = CobylaState::new(); 181 | /// # let cost_old = 1.0f64; 182 | /// # let state = state.cost(vec![cost_old]); 183 | /// # assert!(state.prev_cost.is_none()); 184 | /// # assert_eq!(state.cost.as_ref().unwrap()[0].to_ne_bytes(), 1.0f64.to_ne_bytes()); 185 | /// # let cost = 0.0f64; 186 | /// let state = state.cost(vec![cost]); 187 | /// # assert_eq!(state.prev_cost.as_ref().unwrap()[0].to_ne_bytes(), 1.0f64.to_ne_bytes()); 188 | /// # assert_eq!(state.cost.as_ref().unwrap()[0].to_ne_bytes(), 0.0f64.to_ne_bytes()); 189 | /// ``` 190 | #[must_use] 191 | pub fn cost(mut self, cost: Vec) -> Self { 192 | std::mem::swap(&mut self.prev_cost, &mut self.cost); 193 | self.cost = Some(cost); 194 | self 195 | } 196 | 197 | /// Returns current cost (ie objective) function and constraint values. 198 | /// 199 | /// # Example 200 | /// 201 | /// ``` 202 | /// # use cobyla::CobylaState; 203 | /// # use argmin::core::{State, ArgminFloat}; 204 | /// # let mut state: CobylaState = CobylaState::new(); 205 | /// # state.cost = Some(vec![12.0, 0.1]); 206 | /// let cost = state.get_full_cost(); 207 | /// # assert_eq!(cost.unwrap()[0].to_ne_bytes(), 12.0f64.to_ne_bytes()); 208 | /// # assert_eq!(cost.unwrap()[1].to_ne_bytes(), 0.1f64.to_ne_bytes()); 209 | /// ``` 210 | pub fn get_full_cost(&self) -> Option<&Vec> { 211 | self.cost.as_ref() 212 | } 213 | 214 | /// Returns current cost (ie objective) function and constraint values. 215 | /// 216 | /// # Example 217 | /// 218 | /// ``` 219 | /// # use cobyla::CobylaState; 220 | /// # use argmin::core::{State, ArgminFloat}; 221 | /// # let mut state: CobylaState = CobylaState::new(); 222 | /// # state.best_cost = Some(vec![12.0, 0.1]); 223 | /// let cost = state.get_full_best_cost(); 224 | /// # assert_eq!(cost.unwrap()[0].to_ne_bytes(), 12.0f64.to_ne_bytes()); 225 | /// # assert_eq!(cost.unwrap()[1].to_ne_bytes(), 0.1f64.to_ne_bytes()); 226 | /// ``` 227 | pub fn get_full_best_cost(&self) -> Option<&Vec> { 228 | self.best_cost.as_ref() 229 | } 230 | 231 | /// Returns the rho start value 232 | pub fn rhobeg(&self) -> f64 { 233 | self.rhobeg 234 | } 235 | 236 | /// Returns the rho end value 237 | pub fn get_rhoend(&self) -> f64 { 238 | self.rhoend 239 | } 240 | 241 | /// Returns the level of printing 242 | pub fn get_iprint(&self) -> i32 { 243 | self.iprint 244 | } 245 | 246 | /// Returns cost function calls budget 247 | pub fn get_maxfun(&self) -> i32 { 248 | self.max_iters as i32 249 | } 250 | } 251 | 252 | impl State for CobylaState { 253 | /// Type of parameter vector 254 | type Param = Vec; 255 | /// Floating point precision 256 | type Float = f64; 257 | 258 | /// Create new `CobylaState` instance 259 | /// 260 | /// # Example 261 | /// 262 | /// ``` 263 | /// # extern crate web_time; 264 | /// # use web_time; 265 | /// # use std::collections::HashMap; 266 | /// # use argmin::core::{State, TerminationStatus}; 267 | /// use cobyla::CobylaState; 268 | /// let state: CobylaState = CobylaState::new(); 269 | /// 270 | /// # assert!(state.param.is_none()); 271 | /// # assert!(state.prev_param.is_none()); 272 | /// # assert!(state.best_param.is_none()); 273 | /// # assert!(state.prev_best_param.is_none()); 274 | /// # assert!(state.cost.is_none()); 275 | /// # assert!(state.prev_cost.is_none()); 276 | /// # assert!(state.best_cost.is_none()); 277 | /// # assert!(state.prev_best_cost.is_none()); 278 | /// # assert_eq!(state.target_cost, f64::NEG_INFINITY); 279 | /// # assert_eq!(state.iter, 0); 280 | /// # assert_eq!(state.last_best_iter, 0); 281 | /// # assert_eq!(state.max_iters, std::u64::MAX); 282 | /// # assert_eq!(state.counts, HashMap::new()); 283 | /// # assert_eq!(state.time.unwrap(), web_time::Duration::new(0, 0)); 284 | /// # assert_eq!(state.termination_status, TerminationStatus::NotTerminated); 285 | /// ``` 286 | fn new() -> Self { 287 | CobylaState { 288 | param: None, 289 | prev_param: None, 290 | best_param: None, 291 | prev_best_param: None, 292 | 293 | cost: None, 294 | prev_cost: None, 295 | best_cost: None, 296 | prev_best_cost: None, 297 | target_cost: f64::NEG_INFINITY, 298 | 299 | iter: 0, 300 | last_best_iter: 0, 301 | max_iters: u64::MAX, 302 | counts: HashMap::new(), 303 | time: Some(web_time::Duration::new(0, 0)), 304 | termination_status: TerminationStatus::NotTerminated, 305 | 306 | rhobeg: 0.5, 307 | rhoend: 1e-4, 308 | iprint: 1, 309 | maxfun: 2000, 310 | 311 | cobyla_context: None, 312 | } 313 | } 314 | 315 | /// Checks if the current parameter vector is better than the previous best parameter value. If 316 | /// a new best parameter vector was found, the state is updated accordingly. 317 | /// 318 | /// # Example 319 | /// 320 | /// ``` 321 | /// # use argmin::core::{State, ArgminFloat}; 322 | /// # use cobyla::CobylaState; 323 | /// 324 | /// let mut state: CobylaState = CobylaState::new(); 325 | /// 326 | /// // Simulating a new parameter vector 327 | /// state.param = Some(vec![2.0f64]); 328 | /// state.cost = Some(vec![5.0]); 329 | /// 330 | /// // Calling update 331 | /// state.update(); 332 | /// 333 | /// // Check if update was successful 334 | /// assert_eq!(state.best_param.as_ref().unwrap()[0], 2.0f64); 335 | /// assert_eq!(state.best_cost.as_ref().unwrap()[0], 5.0); 336 | /// assert!(state.is_best()); 337 | /// ``` 338 | fn update(&mut self) { 339 | if let Some(cost) = self.cost.as_ref() { 340 | if let Some(param) = self.param.as_ref().cloned() { 341 | std::mem::swap(&mut self.prev_best_param, &mut self.best_param); 342 | self.best_param = Some(param); 343 | } 344 | std::mem::swap(&mut self.prev_best_cost, &mut self.best_cost); 345 | self.best_cost = Some(cost.clone()); 346 | self.last_best_iter = self.iter; 347 | } 348 | } 349 | 350 | /// Returns a reference to the current parameter vector 351 | /// 352 | /// # Example 353 | /// 354 | /// ``` 355 | /// # use cobyla::CobylaState; 356 | /// # use argmin::core::{State, ArgminFloat}; 357 | /// # let mut state: CobylaState = CobylaState::new(); 358 | /// # assert!(state.param.is_none()); 359 | /// # state.param = Some(vec![1.0, 2.0]); 360 | /// # assert_eq!(state.param.as_ref().unwrap()[0].to_ne_bytes(), 1.0f64.to_ne_bytes()); 361 | /// # assert_eq!(state.param.as_ref().unwrap()[1].to_ne_bytes(), 2.0f64.to_ne_bytes()); 362 | /// let param = state.get_param(); // Option<&P> 363 | /// # assert_eq!(param.as_ref().unwrap()[0].to_ne_bytes(), 1.0f64.to_ne_bytes()); 364 | /// # assert_eq!(param.as_ref().unwrap()[1].to_ne_bytes(), 2.0f64.to_ne_bytes()); 365 | /// ``` 366 | fn get_param(&self) -> Option<&Vec> { 367 | self.param.as_ref() 368 | } 369 | 370 | /// Returns a reference to the current best parameter vector 371 | /// 372 | /// # Example 373 | /// 374 | /// ``` 375 | /// # use cobyla::CobylaState; 376 | /// # use argmin::core::{State, ArgminFloat}; 377 | /// 378 | /// # let mut state: CobylaState = CobylaState::new(); 379 | /// 380 | /// # assert!(state.best_param.is_none()); 381 | /// # state.best_param = Some(vec![1.0, 2.0]); 382 | /// # assert_eq!(state.best_param.as_ref().unwrap()[0].to_ne_bytes(), 1.0f64.to_ne_bytes()); 383 | /// # assert_eq!(state.best_param.as_ref().unwrap()[1].to_ne_bytes(), 2.0f64.to_ne_bytes()); 384 | /// let best_param = state.get_best_param(); // Option<&P> 385 | /// # assert_eq!(best_param.as_ref().unwrap()[0].to_ne_bytes(), 1.0f64.to_ne_bytes()); 386 | /// # assert_eq!(best_param.as_ref().unwrap()[1].to_ne_bytes(), 2.0f64.to_ne_bytes()); 387 | /// ``` 388 | fn get_best_param(&self) -> Option<&Vec> { 389 | self.best_param.as_ref() 390 | } 391 | 392 | /// Sets the termination reason 393 | /// 394 | /// # Example 395 | /// 396 | /// ``` 397 | /// # use cobyla::CobylaState; 398 | /// # use argmin::core::{State, ArgminFloat, TerminationReason, TerminationStatus}; 399 | /// # let mut state: CobylaState = CobylaState::new(); 400 | /// # assert_eq!(state.termination_status, TerminationStatus::NotTerminated); 401 | /// let state = state.terminate_with(TerminationReason::SolverConverged); 402 | /// # assert_eq!(state.termination_status, TerminationStatus::Terminated(TerminationReason::SolverConverged)); 403 | /// ``` 404 | fn terminate_with(mut self, reason: TerminationReason) -> Self { 405 | self.termination_status = TerminationStatus::Terminated(reason); 406 | self 407 | } 408 | 409 | /// Sets the time required so far. 410 | /// 411 | /// # Example 412 | /// 413 | /// ``` 414 | /// # extern crate web_time; 415 | /// # use web_time; 416 | /// # use cobyla::CobylaState; 417 | /// # use argmin::core::{State, ArgminFloat, TerminationReason}; 418 | /// # let mut state: CobylaState = CobylaState::new(); 419 | /// let state = state.time(Some(web_time::Duration::new(0, 12))); 420 | /// # assert_eq!(state.time.unwrap(), web_time::Duration::new(0, 12)); 421 | /// ``` 422 | fn time(&mut self, time: Option) -> &mut Self { 423 | self.time = time; 424 | self 425 | } 426 | 427 | /// Returns current cost function value. 428 | /// 429 | /// # Example 430 | /// 431 | /// ``` 432 | /// # use cobyla::CobylaState; 433 | /// # use argmin::core::{State, ArgminFloat}; 434 | /// # let mut state: CobylaState = CobylaState::new(); 435 | /// # state.cost = Some(vec![12.0]); 436 | /// let cost = state.get_cost(); 437 | /// # assert_eq!(cost.to_ne_bytes(), 12.0f64.to_ne_bytes()); 438 | /// ``` 439 | fn get_cost(&self) -> Self::Float { 440 | match self.cost.as_ref() { 441 | Some(c) => *(c.first().unwrap_or(&f64::INFINITY)), 442 | None => f64::INFINITY, 443 | } 444 | } 445 | 446 | /// Returns current best cost function value. 447 | /// 448 | /// # Example 449 | /// 450 | /// ``` 451 | /// # use cobyla::CobylaState; 452 | /// # use argmin::core::{State, ArgminFloat}; 453 | /// # let mut state: CobylaState = CobylaState::new(); 454 | /// # state.best_cost = Some(vec![12.0]); 455 | /// let best_cost = state.get_best_cost(); 456 | /// # assert_eq!(best_cost.to_ne_bytes(), 12.0f64.to_ne_bytes()); 457 | /// ``` 458 | fn get_best_cost(&self) -> Self::Float { 459 | match self.best_cost.as_ref() { 460 | Some(c) => *(c.first().unwrap_or(&f64::INFINITY)), 461 | None => f64::INFINITY, 462 | } 463 | } 464 | 465 | /// Returns target cost function value. 466 | /// 467 | /// # Example 468 | /// 469 | /// ``` 470 | /// # use cobyla::CobylaState; 471 | /// # use argmin::core::{State, ArgminFloat}; 472 | /// # let mut state: CobylaState = CobylaState::new(); 473 | /// # state.target_cost = 12.0; 474 | /// let target_cost = state.get_target_cost(); 475 | /// # assert_eq!(target_cost.to_ne_bytes(), 12.0f64.to_ne_bytes()); 476 | /// ``` 477 | fn get_target_cost(&self) -> Self::Float { 478 | self.target_cost 479 | } 480 | 481 | /// Returns current number of iterations. 482 | /// 483 | /// # Example 484 | /// 485 | /// ``` 486 | /// # use cobyla::CobylaState; 487 | /// # use argmin::core::{State, ArgminFloat}; 488 | /// # let mut state: CobylaState = CobylaState::new(); 489 | /// # state.iter = 12; 490 | /// let iter = state.get_iter(); 491 | /// # assert_eq!(iter, 12); 492 | /// ``` 493 | fn get_iter(&self) -> u64 { 494 | self.iter 495 | } 496 | 497 | /// Returns iteration number of last best parameter vector. 498 | /// 499 | /// # Example 500 | /// 501 | /// ``` 502 | /// # use cobyla::CobylaState; 503 | /// # use argmin::core::{State, ArgminFloat}; 504 | /// # let mut state: CobylaState = CobylaState::new(); 505 | /// # state.last_best_iter = 12; 506 | /// let last_best_iter = state.get_last_best_iter(); 507 | /// # assert_eq!(last_best_iter, 12); 508 | /// ``` 509 | fn get_last_best_iter(&self) -> u64 { 510 | self.last_best_iter 511 | } 512 | 513 | /// Returns the maximum number of iterations. 514 | /// 515 | /// # Example 516 | /// 517 | /// ``` 518 | /// # use cobyla::CobylaState; 519 | /// # use argmin::core::{State, ArgminFloat}; 520 | /// # let mut state: CobylaState = CobylaState::new(); 521 | /// # state.max_iters = 12; 522 | /// let max_iters = state.get_max_iters(); 523 | /// # assert_eq!(max_iters, 12); 524 | /// ``` 525 | fn get_max_iters(&self) -> u64 { 526 | self.max_iters 527 | } 528 | 529 | /// Returns the termination status. 530 | /// 531 | /// # Example 532 | /// 533 | /// ``` 534 | /// # use argmin::core::{State, ArgminFloat, TerminationStatus}; 535 | /// # use cobyla::CobylaState; 536 | /// # let mut state = CobylaState::new(); 537 | /// let termination_status = state.get_termination_status(); 538 | /// # assert_eq!(*termination_status, TerminationStatus::NotTerminated); 539 | /// ``` 540 | fn get_termination_status(&self) -> &TerminationStatus { 541 | &self.termination_status 542 | } 543 | 544 | /// Returns the termination reason if terminated, otherwise None. 545 | /// 546 | /// # Example 547 | /// 548 | /// ``` 549 | /// # use argmin::core::{State, ArgminFloat, TerminationReason}; 550 | /// # use cobyla::CobylaState; 551 | /// # let mut state = CobylaState::new(); 552 | /// let termination_reason = state.get_termination_reason(); 553 | /// # assert_eq!(termination_reason, None); 554 | /// ``` 555 | fn get_termination_reason(&self) -> Option<&TerminationReason> { 556 | match &self.termination_status { 557 | TerminationStatus::Terminated(reason) => Some(reason), 558 | TerminationStatus::NotTerminated => None, 559 | } 560 | } 561 | 562 | /// Returns the time elapsed since the start of the optimization. 563 | /// 564 | /// # Example 565 | /// 566 | /// ``` 567 | /// # extern crate web_time; 568 | /// # use web_time; 569 | /// # use cobyla::CobylaState; 570 | /// # use argmin::core::{State, ArgminFloat}; 571 | /// # let mut state: CobylaState = CobylaState::new(); 572 | /// let time = state.get_time(); 573 | /// # assert_eq!(time.unwrap(), web_time::Duration::new(0, 0)); 574 | /// ``` 575 | fn get_time(&self) -> Option { 576 | self.time 577 | } 578 | 579 | /// Increments the number of iterations by one 580 | /// 581 | /// # Example 582 | /// 583 | /// ``` 584 | /// # use cobyla::CobylaState; 585 | /// # use argmin::core::{State, ArgminFloat}; 586 | /// # let mut state: CobylaState = CobylaState::new(); 587 | /// # assert_eq!(state.iter, 0); 588 | /// state.increment_iter(); 589 | /// # assert_eq!(state.iter, 1); 590 | /// ``` 591 | fn increment_iter(&mut self) { 592 | self.iter += 1; 593 | } 594 | 595 | /// Set all function evaluation counts to the evaluation counts of another `Problem`. 596 | /// 597 | /// ``` 598 | /// # use std::collections::HashMap; 599 | /// # use cobyla::CobylaState; 600 | /// # use argmin::core::{Problem, State, ArgminFloat}; 601 | /// # let mut state: CobylaState = CobylaState::new(); 602 | /// # assert_eq!(state.counts, HashMap::new()); 603 | /// # state.counts.insert("test2".to_string(), 10u64); 604 | /// # 605 | /// # #[derive(Eq, PartialEq, Debug)] 606 | /// # struct UserDefinedProblem {}; 607 | /// # 608 | /// # let mut problem = Problem::new(UserDefinedProblem {}); 609 | /// # problem.counts.insert("test1", 10u64); 610 | /// # problem.counts.insert("test2", 2); 611 | /// state.func_counts(&problem); 612 | /// # let mut hm = HashMap::new(); 613 | /// # hm.insert("test1".to_string(), 10u64); 614 | /// # hm.insert("test2".to_string(), 2u64); 615 | /// # assert_eq!(state.counts, hm); 616 | /// ``` 617 | fn func_counts(&mut self, problem: &Problem) { 618 | for (k, &v) in problem.counts.iter() { 619 | let count = self.counts.entry(k.to_string()).or_insert(0); 620 | *count = v 621 | } 622 | } 623 | 624 | /// Returns function evaluation counts 625 | /// 626 | /// # Example 627 | /// 628 | /// ``` 629 | /// # use std::collections::HashMap; 630 | /// # use cobyla::CobylaState; 631 | /// # use argmin::core::{State, ArgminFloat}; 632 | /// # let mut state: CobylaState = CobylaState::new(); 633 | /// # assert_eq!(state.counts, HashMap::new()); 634 | /// # state.counts.insert("test2".to_string(), 10u64); 635 | /// let counts = state.get_func_counts(); 636 | /// # let mut hm = HashMap::new(); 637 | /// # hm.insert("test2".to_string(), 10u64); 638 | /// # assert_eq!(*counts, hm); 639 | /// ``` 640 | fn get_func_counts(&self) -> &HashMap { 641 | &self.counts 642 | } 643 | 644 | /// Returns whether the current parameter vector is also the best parameter vector found so 645 | /// far. 646 | /// 647 | /// # Example 648 | /// 649 | /// ``` 650 | /// # use cobyla::CobylaState; 651 | /// # use argmin::core::{State, ArgminFloat}; 652 | /// # let mut state: CobylaState = CobylaState::new(); 653 | /// # state.last_best_iter = 12; 654 | /// # state.iter = 12; 655 | /// let is_best = state.is_best(); 656 | /// # assert!(is_best); 657 | /// # state.last_best_iter = 12; 658 | /// # state.iter = 21; 659 | /// # let is_best = state.is_best(); 660 | /// # assert!(!is_best); 661 | /// ``` 662 | fn is_best(&self) -> bool { 663 | self.last_best_iter == self.iter 664 | } 665 | } 666 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | 3 | mod cobyla; 4 | use nlopt_cobyla::nlopt_constraint; 5 | 6 | mod nlopt_cobyla; 7 | pub use crate::nlopt_cobyla::Func; 8 | 9 | use crate::nlopt_cobyla::{ 10 | cobyla_minimize, 11 | nlopt_constraint_raw_callback, // nlopt_eval_constraint, 12 | nlopt_function_raw_callback, 13 | nlopt_stopping, 14 | NLoptConstraintCfg, 15 | NLoptFunctionCfg, 16 | }; 17 | 18 | mod cobyla_solver; 19 | mod cobyla_state; 20 | pub use crate::cobyla_solver::*; 21 | pub use crate::cobyla_state::*; 22 | 23 | use std::os::raw::c_void; 24 | 25 | /// Failed termination status of the optimization process 26 | #[derive(Debug, Clone, Copy)] 27 | pub enum FailStatus { 28 | Failure, 29 | InvalidArgs, 30 | OutOfMemory, 31 | RoundoffLimited, 32 | ForcedStop, 33 | UnexpectedError, 34 | } 35 | 36 | /// Successful termination status of the optimization process 37 | #[derive(Debug, Clone, Copy)] 38 | pub enum SuccessStatus { 39 | Success, 40 | StopValReached, 41 | FtolReached, 42 | XtolReached, 43 | MaxEvalReached, 44 | MaxTimeReached, 45 | } 46 | 47 | /// Outcome when optimization process fails 48 | type FailOutcome = (FailStatus, Vec, f64); 49 | /// Outcome when optimization process succeeds 50 | type SuccessOutcome = (SuccessStatus, Vec, f64); 51 | 52 | /// Tolerances used as termination criteria. 53 | /// For all, condition is disabled if value is not strictly positive. 54 | /// ```rust 55 | /// # use crate::cobyla::StopTols; 56 | /// let stop_tol = StopTols { 57 | /// ftol_rel: 1e-4, 58 | /// xtol_abs: vec![1e-3; 3], // size should be equal to x dim 59 | /// ..StopTols::default() // default stop conditions are disabled 60 | /// }; 61 | /// ``` 62 | #[derive(Debug, Clone, Default)] 63 | pub struct StopTols { 64 | /// Relative tolerance on function value, algorithm stops when `func(x)` changes by less than `ftol_rel * func(x)` 65 | pub ftol_rel: f64, 66 | /// Absolute tolerance on function value, algorithm stops when `func(x)` change is less than `ftol_rel` 67 | pub ftol_abs: f64, 68 | /// Relative tolerance on optimization parameters, algorithm stops when all `x[i]` changes by less than `xtol_rel * x[i]` 69 | pub xtol_rel: f64, 70 | /// Relative tolerance on optimization parameters, algorithm stops when `x[i]` changes by less than `xtol_abs[i]` 71 | pub xtol_abs: Vec, 72 | } 73 | 74 | /// An enum for specifying the initial change of x which correspond to the `rhobeg` 75 | /// argument of the original Powell's algorithm (hence the name) 76 | pub enum RhoBeg { 77 | /// Used when all x components changes are specified with a single given value 78 | All(f64), 79 | /// Used to set the components with the given x-dim-sized vector 80 | Set(Vec), 81 | } 82 | 83 | /// Minimizes a function using the Constrained Optimization By Linear Approximation (COBYLA) method. 84 | /// 85 | /// ## Arguments 86 | /// 87 | /// * `func` - the function to minimize 88 | /// * `xinit` - n-vector the initial guess 89 | /// * `bounds` - x domain specified as a n-vector of tuple `(lower bound, upper bound)` 90 | /// * `cons` - slice of constraint function intended to be negative at the end 91 | /// * `args` - user data pass to objective and constraint functions 92 | /// * `maxeval` - maximum number of objective function evaluation 93 | /// * `rhobeg`- initial changes to the x component 94 | /// 95 | /// ## Returns 96 | /// 97 | /// The status of the optimization process, the argmin value and the objective function value 98 | /// 99 | /// ## Panics 100 | /// 101 | /// When some vector arguments like `bounds`, `xtol_abs` do not have the same size as `xinit` 102 | /// 103 | /// ## Implementation note: 104 | /// 105 | /// This implementation is a translation of [NLopt](https://github.com/stevengj/nlopt) 2.7.1 106 | /// See also [NLopt SLSQP](https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/#slsqp) documentation. 107 | /// 108 | /// ## Example 109 | /// ``` 110 | /// # use approx::assert_abs_diff_eq; 111 | /// use cobyla::{minimize, Func, RhoBeg}; 112 | /// 113 | /// fn paraboloid(x: &[f64], _data: &mut ()) -> f64 { 114 | /// 10. * (x[0] + 1.).powf(2.) + x[1].powf(2.) 115 | /// } 116 | /// 117 | /// let mut x = vec![1., 1.]; 118 | /// 119 | /// // Constraints definition to be positive eventually: here `x_0 > 0` 120 | /// let cstr1 = |x: &[f64], _user_data: &mut ()| x[0]; 121 | /// let cons: Vec<&dyn Func<()>> = vec![&cstr1]; 122 | /// 123 | /// match minimize( 124 | /// paraboloid, 125 | /// &mut x, 126 | /// &[(-10., 10.), (-10., 10.)], 127 | /// &cons, 128 | /// (), 129 | /// 200, 130 | /// RhoBeg::All(0.5), 131 | /// None 132 | /// ) { 133 | /// Ok((status, x_opt, y_opt)) => { 134 | /// println!("status = {:?}", status); 135 | /// println!("x_opt = {:?}", x_opt); 136 | /// println!("y_opt = {}", y_opt); 137 | /// # assert_abs_diff_eq!(y_opt, 10.0); 138 | /// } 139 | /// Err((e, _, _)) => println!("Optim error: {:?}", e), 140 | /// } 141 | /// ``` 142 | /// 143 | /// ## Algorithm description: 144 | /// 145 | /// COBYLA minimizes an objective function F(X) subject to M inequality 146 | /// constraints on X, where X is a vector of variables that has N components. 147 | /// 148 | /// The algorithm employs linear approximations to the objective and constraint 149 | /// functions, the approximations being formed by linear interpolation at N+1 150 | /// points in the space of the variables. We regard these interpolation points 151 | /// as vertices of a simplex. 152 | /// 153 | /// The parameter RHO controls the size of the simplex and it is reduced 154 | /// automatically from RHOBEG to RHOEND. For each RHO the subroutine tries 155 | /// to achieve a good vector of variables for the current size, and then RHO 156 | /// is reduced until the value RHOEND is reached. 157 | /// 158 | /// Therefore RHOBEG and RHOEND should be set to reasonable initial changes to and the 159 | /// required accuracy in the variables respectively, but this accuracy should be 160 | /// viewed as a subject for experimentation because it is not guaranteed. 161 | /// 162 | /// The subroutine has an advantage over many of its competitors, however, which is 163 | /// that it treats each constraint individually when calculating a change to the 164 | /// variables, instead of lumping the constraints together into a single penalty 165 | /// function. 166 | /// 167 | /// The name of the algorithm is derived from the phrase Constrained 168 | /// Optimization BY Linear Approximations. 169 | /// 170 | /// The user can set the values of RHOBEG and RHOEND, and must provide an 171 | /// initial vector of variables in X. Further, the value of IPRINT should be 172 | /// set to 0, 1, 2 or 3, which controls the amount of printing during the 173 | /// calculation. Specifically, there is no output if IPRINT=0 and there is 174 | /// output only at the end of the calculation if IPRINT=1. 175 | /// Otherwise each new value of RHO and SIGMA is printed. 176 | /// 177 | /// Further, the vector of variables and some function information are 178 | /// given either when RHO is reduced or when each 179 | /// new value of F(X) is computed in the cases IPRINT=2 or IPRINT=3 180 | /// respectively. Here SIGMA is a penalty parameter, it being assumed that a 181 | /// change to X is an improvement if it reduces the merit function: 182 | /// 183 | /// F(X)+SIGMA*MAX(0.0,-C1(X),-C2(X),...,-CM(X)), 184 | /// 185 | /// where C1, C2, ..., CM denote the constraint functions that should become 186 | /// nonnegative eventually, at least to the precision of RHOEND. In the 187 | /// printed output the displayed term that is multiplied by SIGMA is 188 | /// called MAXCV, which stands for 'MAXimum Constraint Violation'. 189 | /// 190 | /// This implementation is a translation/adaptation of [NLopt](https://github.com/stevengj/nlopt) 2.7.1 191 | /// See [NLopt COBYLA](https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/#cobyla-constrained-optimization-by-linear-approximations) documentation. 192 | #[allow(clippy::useless_conversion)] 193 | #[allow(clippy::too_many_arguments)] 194 | pub fn minimize, G: Func, U: Clone>( 195 | func: F, 196 | xinit: &[f64], 197 | bounds: &[(f64, f64)], 198 | cons: &[G], 199 | args: U, 200 | maxeval: usize, 201 | rhobeg: RhoBeg, 202 | stop_tol: Option, 203 | ) -> Result { 204 | let fn_cfg = Box::new(NLoptFunctionCfg { 205 | objective_fn: func, 206 | user_data: args.clone(), 207 | }); 208 | let fn_cfg_ptr = Box::into_raw(fn_cfg) as *mut c_void; 209 | let mut cstr_tol = 0.0; // no cstr tolerance 210 | 211 | let mut cstr_cfg = cons 212 | .iter() 213 | .map(|c| { 214 | let c_cfg = Box::new(NLoptConstraintCfg { 215 | constraint_fn: c as &dyn Func, 216 | user_data: args.clone(), 217 | }); 218 | let c_cfg_ptr = Box::into_raw(c_cfg) as *mut c_void; 219 | 220 | nlopt_constraint { 221 | m: 1, 222 | f: Some(nlopt_constraint_raw_callback::), 223 | pre: None, 224 | mf: None, 225 | f_data: c_cfg_ptr, 226 | tol: &mut cstr_tol, 227 | } 228 | }) 229 | .collect::>(); 230 | 231 | let mut x = vec![0.; xinit.len()]; 232 | x.copy_from_slice(xinit); 233 | let n = x.len() as u32; 234 | let m = cons.len() as u32; 235 | 236 | if bounds.len() != x.len() { 237 | panic!( 238 | "{}", 239 | format!( 240 | "Minimize Error: Bounds and x should have same size! Got {} for bounds and {} for x.", 241 | bounds.len(), 242 | x.len() 243 | ) 244 | ) 245 | } 246 | let lbs: Vec = bounds.iter().map(|b| b.0).collect(); 247 | let ubs: Vec = bounds.iter().map(|b| b.1).collect(); 248 | let x_weights = vec![0.; n as usize]; 249 | let mut dx = match rhobeg { 250 | RhoBeg::All(val) => vec![val; n as usize], 251 | RhoBeg::Set(val) => { 252 | if val.len() != n as usize { 253 | panic!( 254 | "{}", 255 | format!( 256 | "Minimize Error: xtol_abs should have x dim size ({}), got {}", 257 | n, 258 | val.len() 259 | ) 260 | ) 261 | } else { 262 | val 263 | } 264 | } 265 | }; 266 | let mut minf = f64::INFINITY; 267 | let mut nevals_p = 0; 268 | let mut force_stop = 0; 269 | 270 | let stop_tol = stop_tol.unwrap_or_default(); 271 | let xtol_abs = if stop_tol.xtol_abs.is_empty() { 272 | std::ptr::null() 273 | } else if stop_tol.xtol_abs.len() != n as usize { 274 | panic!( 275 | "{}", 276 | format!( 277 | "Minimize Error: xtol_abs should have x dim size ({}), got {}", 278 | n, 279 | stop_tol.xtol_abs.len() 280 | ) 281 | ); 282 | } else { 283 | stop_tol.xtol_abs.as_ptr() 284 | }; 285 | let mut stop = nlopt_stopping { 286 | n, 287 | minf_max: -f64::INFINITY, 288 | ftol_rel: stop_tol.ftol_rel, 289 | ftol_abs: stop_tol.ftol_abs, 290 | xtol_rel: stop_tol.xtol_rel, 291 | xtol_abs, 292 | x_weights: x_weights.as_ptr(), 293 | nevals_p: &mut nevals_p, 294 | maxeval: maxeval as i32, 295 | maxtime: 0.0, 296 | start: 0.0, 297 | force_stop: &mut force_stop, 298 | stop_msg: "".to_string(), 299 | }; 300 | 301 | let status = unsafe { 302 | cobyla_minimize::( 303 | n.into(), 304 | Some(nlopt_function_raw_callback::), 305 | fn_cfg_ptr, 306 | m.into(), 307 | cstr_cfg.as_mut_ptr(), 308 | 0, 309 | std::ptr::null_mut(), 310 | lbs.as_ptr(), 311 | ubs.as_ptr(), 312 | x.as_mut_ptr(), 313 | &mut minf, 314 | &mut stop, 315 | dx.as_mut_ptr(), 316 | ) 317 | }; 318 | 319 | // Convert the raw pointer back into a Box with the B::from_raw function, 320 | // allowing the Box destructor to perform the cleanup. 321 | unsafe { 322 | let _ = Box::from_raw(fn_cfg_ptr as *mut NLoptFunctionCfg); 323 | }; 324 | 325 | match status { 326 | -1 => Err((FailStatus::Failure, x, minf)), 327 | -2 => Err((FailStatus::InvalidArgs, x, minf)), 328 | -3 => Err((FailStatus::OutOfMemory, x, minf)), 329 | -4 => Err((FailStatus::RoundoffLimited, x, minf)), 330 | -5 => Err((FailStatus::ForcedStop, x, minf)), 331 | 1 => Ok((SuccessStatus::Success, x, minf)), 332 | 2 => Ok((SuccessStatus::StopValReached, x, minf)), 333 | 3 => Ok((SuccessStatus::FtolReached, x, minf)), 334 | 4 => Ok((SuccessStatus::XtolReached, x, minf)), 335 | 5 => Ok((SuccessStatus::MaxEvalReached, x, minf)), 336 | 6 => Ok((SuccessStatus::MaxTimeReached, x, minf)), 337 | _ => Err((FailStatus::UnexpectedError, x, minf)), 338 | } 339 | } 340 | 341 | #[cfg(test)] 342 | mod tests { 343 | use super::*; 344 | use approx::assert_abs_diff_eq; 345 | 346 | use crate::nlopt_cobyla::cobyla_minimize; 347 | use crate::nlopt_cobyla::nlopt_stopping; 348 | 349 | ///////////////////////////////////////////////////////////////////////// 350 | // Second problem (see cobyla.c case 6) 351 | 352 | fn raw_paraboloid( 353 | _n: libc::c_uint, 354 | x: *const libc::c_double, 355 | _gradient: *mut libc::c_double, 356 | _func_data: *mut libc::c_void, 357 | ) -> libc::c_double { 358 | unsafe { 359 | let r1 = *x.offset(0) + 1.0; 360 | let r2 = *x.offset(1); 361 | 10.0 * (r1 * r1) + (r2 * r2) as libc::c_double 362 | } 363 | } 364 | 365 | #[test] 366 | fn test_cobyla_minimize() { 367 | let mut x = vec![1., 1.]; 368 | let mut lb = vec![-10.0, -10.0]; 369 | let mut ub = vec![10.0, 10.0]; 370 | let mut dx = vec![0.5, 0.5]; 371 | let mut minf = f64::INFINITY; 372 | let mut nevals_p = 0; 373 | let mut force_stop = 0; 374 | 375 | let mut stop = nlopt_stopping { 376 | n: 2, 377 | minf_max: -f64::INFINITY, 378 | ftol_rel: 0.0, 379 | ftol_abs: 0.0, 380 | xtol_rel: 0.0, 381 | xtol_abs: std::ptr::null(), 382 | x_weights: std::ptr::null(), 383 | nevals_p: &mut nevals_p, 384 | maxeval: 1000, 385 | maxtime: 0.0, 386 | start: 0.0, 387 | force_stop: &mut force_stop, 388 | stop_msg: "".to_string(), 389 | }; 390 | 391 | let res = unsafe { 392 | cobyla_minimize::<()>( 393 | 2, 394 | Some(raw_paraboloid), 395 | std::ptr::null_mut(), 396 | 0, 397 | std::ptr::null_mut(), 398 | 0, 399 | std::ptr::null_mut(), 400 | lb.as_mut_ptr(), 401 | ub.as_mut_ptr(), 402 | x.as_mut_ptr(), 403 | &mut minf, 404 | &mut stop, 405 | dx.as_mut_ptr(), 406 | ) 407 | }; 408 | 409 | println!("status = {:?}", res); 410 | println!("x = {:?}", x); 411 | 412 | assert_abs_diff_eq!(x.as_slice(), [-1., 0.].as_slice(), epsilon = 1e-4); 413 | } 414 | 415 | fn paraboloid(x: &[f64], _data: &mut ()) -> f64 { 416 | 10. * (x[0] + 1.).powf(2.) + x[1].powf(2.) 417 | } 418 | 419 | #[test] 420 | fn test_paraboloid() { 421 | let xinit = vec![1., 1.]; 422 | 423 | // let mut cons: Vec<&dyn Func<()>> = vec![]; 424 | let mut cons: Vec<&dyn Func<()>> = vec![]; 425 | let cstr1 = |x: &[f64], _user_data: &mut ()| x[0]; 426 | cons.push(&cstr1 as &dyn Func<()>); 427 | 428 | // x_opt = [0, 0] 429 | match minimize( 430 | paraboloid, 431 | &xinit, 432 | &[(-10., 10.), (-10., 10.)], 433 | &cons, 434 | (), 435 | 200, 436 | RhoBeg::All(0.5), 437 | None, 438 | ) { 439 | Ok((_, x, _)) => { 440 | let exp = [0., 0.]; 441 | for (act, exp) in x.iter().zip(exp.iter()) { 442 | assert_abs_diff_eq!(act, exp, epsilon = 1e-3); 443 | } 444 | } 445 | Err((status, _, _)) => { 446 | panic!("{}", format!("Error status : {:?}", status)); 447 | } 448 | } 449 | } 450 | 451 | fn fletcher9115(x: &[f64], _user_data: &mut ()) -> f64 { 452 | -x[0] - x[1] 453 | } 454 | 455 | fn cstr1(x: &[f64], _user_data: &mut ()) -> f64 { 456 | x[1] - x[0] * x[0] 457 | } 458 | fn cstr2(x: &[f64], _user_data: &mut ()) -> f64 { 459 | 1. - x[0] * x[0] - x[1] * x[1] 460 | } 461 | 462 | #[test] 463 | fn test_fletcher9115() { 464 | let xinit = vec![1., 1.]; 465 | 466 | let cons = vec![&cstr1 as &dyn Func<()>, &cstr2 as &dyn Func<()>]; 467 | 468 | let stop_tol = StopTols { 469 | ftol_rel: 1e-4, 470 | xtol_rel: 1e-4, 471 | ..StopTols::default() 472 | }; 473 | 474 | match minimize( 475 | fletcher9115, 476 | &xinit, 477 | &[(-10., 10.), (-10., 10.)], 478 | &cons, 479 | (), 480 | 200, 481 | RhoBeg::All(0.5), 482 | Some(stop_tol), 483 | ) { 484 | Ok((_, x, _)) => { 485 | let sqrt_0_5: f64 = 0.5_f64.sqrt(); 486 | let exp = [sqrt_0_5, sqrt_0_5]; 487 | for (act, exp) in x.iter().zip(exp.iter()) { 488 | assert_abs_diff_eq!(act, exp, epsilon = 1e-3); 489 | } 490 | } 491 | Err((status, _, _)) => { 492 | println!("Error status : {:?}", status); 493 | panic!("Test fail"); 494 | } 495 | } 496 | } 497 | 498 | fn xsinx(x: &[f64], _user_data: &mut ()) -> f64 { 499 | //(x - 3.5) * ((x - 3.5) / std::f64::consts::PI).mapv(|v| v.sin()) 500 | (x[0] - 3.5) * f64::sin((x[0] - 3.5) / std::f64::consts::PI) 501 | } 502 | 503 | #[test] 504 | fn test_xsinx() { 505 | let xinit = vec![10.]; 506 | 507 | // let mut cons: Vec<&dyn Func<()>> = vec![]; 508 | let mut cons: Vec<&dyn Func<()>> = vec![]; 509 | let cstr1 = |x: &[f64], _user_data: &mut ()| 17. - x[0]; 510 | cons.push(&cstr1 as &dyn Func<()>); 511 | 512 | // x_opt = [0, 0] 513 | match minimize( 514 | xsinx, 515 | &xinit, 516 | &[(0., 25.)], 517 | &cons, 518 | (), 519 | 200, 520 | RhoBeg::All(0.5), 521 | None, 522 | ) { 523 | Ok((_, x, _)) => { 524 | //let exp = [18.935]; 525 | let exp = [17.]; 526 | for (act, exp) in x.iter().zip(exp.iter()) { 527 | assert_abs_diff_eq!(act, exp, epsilon = 1e-2); 528 | } 529 | } 530 | Err((status, _, _)) => { 531 | panic!("{}", format!("Error status : {:?}", status)); 532 | } 533 | } 534 | } 535 | } 536 | --------------------------------------------------------------------------------