Skip to content

Commit

Permalink
All algorithms yield (x,info)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmt committed Oct 20, 2023
1 parent 762a1a1 commit f09c8df
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 310 deletions.
18 changes: 17 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,26 @@

- Objective function and non-linear constraints for `cobyla`:
- Non-linear equality constraints can be specified by keyword `nonlinear_eq`.
- The objective function is called as `f(x)` as for other algorithms.
- The objective function is called as `f(x)` like in other algorithms.
- The functions implementing the non-linear constraints are passed by
keywords `nonlinear_eq` and `nonlinear_ineq`.

- Algorithms have a more similar interface:
- All algorithms have the same positional input, only the available keywords
may change.
- All algorithms have the same convention for the objective function.
Non-linear constraints, if any, are provided by other user-defined
functions.
- All algorithms yield a 2-tuple `(x,info)` with `x` an approximate solution
(provided algorithm was successful) and `info` a structured object
collecting other outputs from the algorithm. The following properties are
available for all algorithms: `info.fx` is the objective function value
`f(x)`, `info.nf` is the number of evaluations of the objective function,
and `info.status` is the termination status of the algorithm.
- `issuccess(info)` yields whether algorithm was successful.
- `PRIMA.reason(info)` yields a textual description of the termination status
of the algorithm.

## Version 0.1.1

- Keywords for other constraints than bounds have been renamed as
Expand Down
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ authors = ["Éric Thiébaut <eric.thiebaut@univ-lyon1.fr> and contributors"]
version = "0.1.1"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
PRIMA_jll = "eead6e0c-2d5b-5641-a95c-b722de96d551"
TypeUtils = "c3b1956e-8857-4d84-9b79-890df85b1e67"

Expand Down
105 changes: 53 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,62 +82,67 @@ These methods are called as follows:

``` julia
using PRIMA
x, fx, nf, rc = uobyqa(f, x0; kwds...)
x, fx, nf, rc = newuoa(f, x0; kwds...)
x, fx, nf, rc = bobyqa(f, x0; kwds...)
x, fx, nf, rc, cstrv = cobyla(f, x0; kwds...)
x, fx, nf, rc, cstrv = lincoa(f, x0; kwds...)
x, info = uobyqa(f, x0; kwds...)
x, info = newuoa(f, x0; kwds...)
x, info = bobyqa(f, x0; kwds...)
x, info = cobyla(f, x0; kwds...)
x, info = lincoa(f, x0; kwds...)
```

where `f` is the objective function and `x0` is the initial solution.
Constraints and options may be specified by keywords `kwds...` (see below). The
result is the 4-tuple `(x, fx, nf, rc)` or the 5-tuple `(x, fx, nf, rc, cstrv)`
where `x` is the (approximate) solution found by the algorithm, `fx` is the
value of `f(x)`, `nf` is the number of calls to `f`, `rc` is a status code (an
enumeration value of type `PRIMA.Status`), and `cstrv` is the amount of
constraint violation.
where `f` is the objective function and `x0` specifies the initial values of
the variables (and is left unchanged). Constraints and options may be specified
by keywords `kwds...` (see below).

For example, `rc` can be:
The objective function is called as `f(x)` with `x` the variables, it must
implement the following signature:

- `PRIMA.SMALL_TR_RADIUS` if the radius of the trust region becomes smaller or
equal the value of keyword `rhobeg`, in other words, the algorithm has
converged in terms of variable precision;
``` julia
f(x::Vector{Cdouble})::Real
```

- `PRIMA.FTARGET_ACHIEVED` if the objective function is smaller of equal the
value of keyword `ftarget`, in other words, the algorithm has converged in
terms of function value.
All the algorithms return a 2-tuple `(x, info)` with `x` the variables and
`info` a structured object collecting all other information. If
`issuccess(info)` is true, then the algorithm was successful and `x` is an
approximate solution of the problem.

There are other possibilities which all indicate an error. Calling:
The output `info` has the following properties:

``` julia
PRIMA.reason(rc)
info.fx # value of the objective function f(x) on return
info.nf # number of calls to the objective function
info.status # final status code
info.cstrv # amount of constraints violation, 0.0 if unconstrained
info.nl_eq # non-linear equality constraints, empty vector if none
info.nl_ineq # non-linear inequality constraints, empty vector if none
```

yields a textual explanation about the reason that leads the algorithm to stop.

For all algorithms, except `cobyla`, the user-defined function takes a single
argument, the variables of the problem, and returns the value of the objective
function. It has the following signature:
Calling one of:

``` julia
function objfun(x::Vector{Cdouble})
return f(x)
end
issuccess(info)
issuccess(info.status)
```

The `cobyla` algorithm can account for `m` non-linear constraints expressed by
`c(x) ≤ 0`. For this algorithm, the user-defined function takes two arguments,
the `x` variables `x` and the values taken by the constraints `cx`, it shall
overwrite the array of constraints with `cx = c(x)` and return the value of the
objective function. It has the following signature:
yield whether the algorithm has converged. If this is the case, `info.status`
can be one of:

- `PRIMA.SMALL_TR_RADIUS` if the radius of the trust region becomes smaller or
equal the value of keyword `rhobeg`, in other words, the algorithm has
converged in terms of variable precision;

- `PRIMA.FTARGET_ACHIEVED` if the objective function is smaller of equal the
value of keyword `ftarget`, in other words, the algorithm has converged in
terms of function value.

There are other possibilities which all indicate a failure. Calling one of:

``` julia
function objfuncon(x::Vector{Cdouble}, cx::Vector{Cdouble})
copyto!(cx, c(x)) # set constraints
return f(x) # return value of objective function
end
PRIMA.reason(info)
PRIMA.reason(info.status)
```

yield a textual explanation about the reason that leads the algorithm to stop.

The keywords allowed by the different algorithms are summarized by the
following table.

Expand Down Expand Up @@ -169,8 +174,8 @@ Assuming `n = length(x)` is the number of variables, then:
`PRIMA.FTARGET_ACHIEVED` is returned.

- `iprint` (default value `PRIMA.MSG_NONE`) sets the level of verbosity of the
algorithm. Possible values are `PRIMA.MSG_EXIT`, `PRIMA.MSG_RHO`, or
`PRIMA.MSG_FEVL`.
algorithm. Possible values are `PRIMA.MSG_EXIT`, `PRIMA.MSG_RHO`, or
`PRIMA.MSG_FEVL`.

- `maxfun` (default `100n`) is the maximum number of function evaluations
allowed for the algorithm. If the number of calls to `f(x)` exceeds this
Expand All @@ -183,22 +188,18 @@ Assuming `n = length(x)` is the number of variables, then:
M.J.D. Powell.

- `xl` and `xu` (default `fill(+Inf, n)` and `fill(-Inf, n)`) are the
elementwise lower and upper bounds for the variables. Feasible variables are
such that `xl ≤ x ≤ xu` (elementwise).
element-wise lower and upper bounds for the variables. Feasible variables are
such that `xl ≤ x ≤ xu`.

- `nonlinear_eq` (default `nothing`) may be specified with a function, say
`c_eq`, implementing `n_eq` non-linear equality constraints defined by
`c_eq(x) = 0`. If the caller is interested in the values of `c_eq(x)` at the
returned solution, the keyword may be set with a 2-tuple `(v_eq, c_eq)` or
`(c_eq, v_eq)` with `v_eq` a vector of `n_eq` floating-point values to store
`c_eq(x)`.
`c_eq`, implementing non-linear equality constraints defined by `c_eq(x) =
0`. On return, the values of the non-linear equality constraints are given by
`info.nl_eq` to save calling `c_eq(x)`.

- `nonlinear_ineq` (default `nothing`) may be specified with a function, say
`c_ineq`, implementing `n_ineq` non-linear inequality constraints defined by
`c_ineq(x) ≤ 0`. If the caller is interested in the values of `c_ineq(x)` at
the returned solution, the keyword may be set with a 2-tuple `(v_ineq,
c_ineq)` or `(c_ineq, v_ineq)` with `v_ineq` a vector of `n_ineq`
floating-point values to store `c_ineq(x)`.
`c_ineq`, implementing non-linear inequality constraints defined by
`c_ineq(x) ≤ 0`. On return, the values of the non-linear inequality
constraints are given by `info.nl_ineq` to save calling `c_ineq(x)`.

- `linear_eq` (default `nothing`) may be specified as a tuple `(Aₑ,bₑ)` to
impose the linear equality constraints `Aₑ⋅x = bₑ`.
Expand Down
Loading

0 comments on commit f09c8df

Please sign in to comment.