diff --git a/src/problems/optimization_problems.jl b/src/problems/optimization_problems.jl index b5e66482d..aec01cb3b 100644 --- a/src/problems/optimization_problems.jl +++ b/src/problems/optimization_problems.jl @@ -31,6 +31,8 @@ OptimizationProblem{iip}(f, u0, p = SciMLBase.NullParameters(),; lcons = nothing, ucons = nothing, sense = nothing, + num_dimensions = nothing, + fitness_scheme = nothing, kwargs...) ``` @@ -77,7 +79,8 @@ Any extra keyword arguments are captured to be sent to the optimizers. Defaults to `nothing`, implying no upper bounds for the constraints (i.e. the constraint bound is `Inf`) * `sense`: the objective sense, can take `MaxSense` or `MinSense` from Optimization.jl. * `kwargs`: the keyword arguments passed on to the solvers. - +* `num_dimensions`: For BBO optimization. +* `fitness_scheme`: For BBO optimization. ## Inequality and Equality Constraints Both inequality and equality constraints are defined by the `f.cons` function in the [`OptimizationFunction`](https://docs.sciml.ai/Optimization/stable/API/optimization_function/#optfunction) @@ -95,7 +98,7 @@ Note that these vectors must be sized to match the number of constraints, with o As described above the second argument of the objective definition can take a full batch or a [`DataLoader`](https://juliaml.github.io/MLUtils.jl/stable/api/#MLUtils.DataLoader) object for mini-batching which is useful for stochastic optimization solvers. Thus the data either as an Array or a `DataLoader` object should be passed as the third argument of the `OptimizationProblem` constructor. For an example of how to use this data handling, see the `Sophia` example in the [Optimization.jl documentation](https://docs.sciml.ai/Optimization/dev/optimization_packages/optimization) or the [mini-batching tutorial](https://docs.sciml.ai/Optimization/dev/tutorials/minibatch/). """ -struct OptimizationProblem{iip, F, uType, P, LB, UB, I, LC, UC, S, K} <: +struct OptimizationProblem{iip, F, uType, P, LB, UB, I, LC, UC, S, ND, FS, K} <: AbstractOptimizationProblem{iip} f::F u0::uType @@ -106,6 +109,8 @@ struct OptimizationProblem{iip, F, uType, P, LB, UB, I, LC, UC, S, K} <: lcons::LC ucons::UC sense::S + num_dimensions::ND + fitness_scheme::FS kwargs::K @add_kwonly function OptimizationProblem{iip}( f::Union{OptimizationFunction{iip}, MultiObjectiveOptimizationFunction{iip}}, @@ -113,14 +118,14 @@ struct OptimizationProblem{iip, F, uType, P, LB, UB, I, LC, UC, S, K} <: p = NullParameters(); lb = nothing, ub = nothing, int = nothing, lcons = nothing, ucons = nothing, - sense = nothing, kwargs...) where {iip} + sense = nothing, num_dimensions = nothing, fitness_scheme = nothing, kwargs...) where {iip} if xor(lb === nothing, ub === nothing) error("If any of `lb` or `ub` is provided, both must be provided.") end warn_paramtype(p) new{iip, typeof(f), typeof(u0), typeof(p), typeof(lb), typeof(ub), typeof(int), typeof(lcons), typeof(ucons), - typeof(sense), typeof(kwargs)}(f, u0, p, lb, ub, int, lcons, ucons, sense, + typeof(sense), typeof(num_dimensions), typeof(fitness_scheme), typeof(kwargs)}(f, u0, p, lb, ub, int, lcons, ucons, sense, num_dimensions, fitness_scheme, kwargs) end end diff --git a/src/remake.jl b/src/remake.jl index a078b3060..151a91fab 100644 --- a/src/remake.jl +++ b/src/remake.jl @@ -379,6 +379,8 @@ function remake(prob::OptimizationProblem; lcons = missing, ucons = missing, sense = missing, + num_dimensions = missing, + fitness_scheme = missing, kwargs = missing, interpret_symbolicmap = true, use_defaults = false, @@ -406,16 +408,24 @@ function remake(prob::OptimizationProblem; sense = prob.sense end + if num_dimensions === missing + num_dimensions = prob.num_dimensions + end + + if fitness_scheme === missing + fitness_scheme = prob.fitness_scheme + end + if kwargs === missing OptimizationProblem{isinplace(prob)}(f = f, u0 = u0, p = p, lb = lb, ub = ub, int = int, lcons = lcons, ucons = ucons, - sense = sense; prob.kwargs..., _kwargs...) + sense = sense, num_dimensions = num_dimensions, fitness_scheme = fitness_scheme; prob.kwargs..., _kwargs...) else OptimizationProblem{isinplace(prob)}(f = f, u0 = u0, p = p, lb = lb, ub = ub, int = int, lcons = lcons, ucons = ucons, - sense = sense; kwargs...) + sense = sense, num_dimensions = num_dimensions, fitness_scheme = fitness_scheme; kwargs...) end end diff --git a/src/scimlfunctions.jl b/src/scimlfunctions.jl index 586ebebb7..72e436277 100644 --- a/src/scimlfunctions.jl +++ b/src/scimlfunctions.jl @@ -1930,11 +1930,104 @@ end """ $(TYPEDEF) + +A representation of a multi-objective optimization problem, where multiple objective functions `f1, f2, ..., fn` are to be minimized: + +'''math +\\min_{u} F(u, p) = [f1(u, p), f2(u, p), ..., fn(u, p)] +''' + +`F` represents a vector of objective functions, where `u` are the optimization variables and `p` are fixed parameters or data. This struct defines all related functions such as Jacobians, Hessians, constraint functions, and their derivatives needed to solve multi-objective optimization problems. + +## Constructor + +```julia +MultiObjectiveOptimizationFunction{iip}(F, adtype::AbstractADType = NoAD(); + jac = nothing, hess = nothing, hv = nothing, + cons = nothing, cons_j = nothing, cons_jvp = nothing, + cons_vjp = nothing, cons_h = nothing, + hess_prototype = nothing, + cons_jac_prototype = nothing, + cons_hess_prototype = nothing, + observed = __has_observed(F) ? F.observed : DEFAULT_OBSERVED_NO_TIME, + lag_h = nothing, + hess_colorvec = __has_colorvec(F) ? F.colorvec : nothing, + cons_jac_colorvec = __has_colorvec(F) ? F.colorvec : nothing, + cons_hess_colorvec = __has_colorvec(F) ? F.colorvec : nothing, + lag_hess_colorvec = nothing, + sys = __has_sys(F) ? F.sys : nothing) +``` + +## Positional Arguments + +- `F(u, p, args...)`: The vector-valued multi-objective function `F` to be minimized. `u` is the vector of decision variables, + `p` contains the parameters, and extra arguments can be passed as needed. Each element of `F` corresponds to an individual objective function `f1, f2, ..., fn`. + +## Keyword Arguments +- `jac(J, u, p)` or `J = jac(u, p)`: Jacobian of the multi-objective function `F` with respect to `u`. Can accept additional arguments: `jac(J, u, p, args...)`. +- `hess(H, u, p)` or `H = hess(u, p)`: Hessian matrix of the multi-objective function `F`. Accepts additional arguments: `hess(H, u, p, args...)`. +- `hv(Hv, u, v, p)` or `Hv = hv(u, v, p)`: Hessian-vector product for the multi-objective function `F`. Extra arguments: `hv(Hv, u, v, p, args...)`. +- `cons(res,u,p)` or `res=cons(u,p)` : the constraints function, should mutate the passed `res` array + with value of the `i`th constraint, evaluated at the current values of variables + inside the optimization routine. This takes just the function evaluations + and the equality or inequality assertion is applied by the solver based on the constraint + bounds passed as `lcons` and `ucons` to [`OptimizationProblem`](@ref), in case of equality + constraints `lcons` and `ucons` should be passed equal values. +- `cons_j(J,u,p)` or `J=cons_j(u,p)`: the Jacobian of the constraints. +- `cons_jvp(Jv,u,v,p)` or `Jv=cons_jvp(u,v,p)`: the Jacobian-vector product of the constraints. +- `cons_vjp(Jv,u,v,p)` or `Jv=cons_vjp(u,v,p)`: the Jacobian-vector product of the constraints. +- `cons_h(H,u,p)` or `H=cons_h(u,p)`: the Hessian of the constraints, provided as + an array of Hessians with `res[i]` being the Hessian with respect to the `i`th output on `cons`. +- `hess_prototype`: a prototype matrix matching the type that matches the Hessian. For example, + if the Hessian is tridiagonal, then an appropriately sized `Hessian` matrix can be used + as the prototype and optimization solvers will specialize on this structure where possible. Non-structured + sparsity patterns should use a `SparseMatrixCSC` with a correct sparsity pattern for the Hessian. + The default is `nothing`, which means a dense Hessian. +- `cons_jac_prototype`: a prototype matrix matching the type that matches the constraint Jacobian. + The default is `nothing`, which means a dense constraint Jacobian. +- `cons_hess_prototype`: a prototype matrix matching the type that matches the constraint Hessian. + This is defined as an array of matrices, where `hess[i]` is the Hessian w.r.t. the `i`th output. + For example, if the Hessian is sparse, then `hess` is a `Vector{SparseMatrixCSC}`. + The default is `nothing`, which means a dense constraint Hessian. +- `lag_h(res,u,sigma,mu,p)` or `res=lag_h(u,sigma,mu,p)`: the Hessian of the Lagrangian, + where `sigma` is a multiplier of the cost function and `mu` are the Lagrange multipliers + multiplying the constraints. This can be provided instead of `hess` and `cons_h` + to solvers that directly use the Hessian of the Lagrangian. +- `hess_colorvec`: a color vector according to the SparseDiffTools.jl definition for the sparsity + pattern of the `hess_prototype`. This specializes the Hessian construction when using + finite differences and automatic differentiation to be computed in an accelerated manner + based on the sparsity pattern. Defaults to `nothing`, which means a color vector will be + internally computed on demand when required. The cost of this operation is highly dependent + on the sparsity pattern. +- `cons_jac_colorvec`: a color vector according to the SparseDiffTools.jl definition for the sparsity + pattern of the `cons_jac_prototype`. +- `cons_hess_colorvec`: an array of color vector according to the SparseDiffTools.jl definition for + the sparsity pattern of the `cons_hess_prototype`. +-`num_dimensions`: the number of dimensions of the constraint box for OptimizationBBO.jl. +-`fitness_scheme`: the fitness scheme for OptimizationBBO.jl. + +When [Symbolic Problem Building with ModelingToolkit](https://docs.sciml.ai/Optimization/stable/tutorials/symbolic/) interface is used the following arguments are also relevant: + +- `observed`: an algebraic combination of optimization variables that is of interest to the user + which will be available in the solution. This can be single or multiple expressions. +- `sys`: field that stores the `OptimizationSystem`. + +## iip: In-Place vs Out-Of-Place + +For more details on this argument, see the ODEFunction documentation. + +## specialize: Controlling Compilation and Specialization + +For more details on this argument, see the ODEFunction documentation. + +## Fields + +The fields of the MultiObjectiveOptimizationFunction type directly match the names of the inputs. """ struct MultiObjectiveOptimizationFunction{ iip, AD, F, J, H, HV, C, CJ, CJV, CVJ, CH, HP, CJP, CHP, O, - EX, CEX, SYS, LH, LHP, HCV, CJCV, CHCV, LHCV} <: + EX, CEX, SYS, LH, LHP, HCV, CJCV, CHCV, LHCV, ND, FS} <: AbstractOptimizationFunction{iip} f::F adtype::AD @@ -1959,6 +2052,8 @@ struct MultiObjectiveOptimizationFunction{ cons_jac_colorvec::CJCV cons_hess_colorvec::CHCV lag_hess_colorvec::LHCV + num_dimensions::ND + fitness_scheme::FS end """ @@ -3885,7 +3980,9 @@ function MultiObjectiveOptimizationFunction{iip}(f, adtype::AbstractADType = NoA nothing, cons_hess_colorvec = __has_colorvec(f) ? f.colorvec : nothing, - lag_hess_colorvec = nothing) where {iip} + lag_hess_colorvec = nothing, + num_dimensions = 0, + fitness_scheme = nothing) where {iip} isinplace(f, 2; has_two_dispatches = false, isoptimization = true) sys = sys_or_symbolcache(sys, syms, paramsyms) MultiObjectiveOptimizationFunction{ @@ -3899,14 +3996,14 @@ function MultiObjectiveOptimizationFunction{iip}(f, adtype::AbstractADType = NoA typeof(expr), typeof(cons_expr), typeof(sys), typeof(lag_h), typeof(lag_hess_prototype), typeof(hess_colorvec), typeof(cons_jac_colorvec), typeof(cons_hess_colorvec), - typeof(lag_hess_colorvec) + typeof(lag_hess_colorvec), typeof(num_dimensions), typeof(fitness_scheme) }(f, adtype, jac, hess, hv, cons, cons_j, cons_jvp, cons_vjp, cons_h, hess_prototype, cons_jac_prototype, cons_hess_prototype, observed, expr, cons_expr, sys, lag_h, lag_hess_prototype, hess_colorvec, cons_jac_colorvec, - cons_hess_colorvec, lag_hess_colorvec) + cons_hess_colorvec, lag_hess_colorvec, num_dimensions, fitness_scheme) end function BVPFunction{iip, specialize, twopoint}(f, bc;