From 832ff98334b046e6b09121d4610253665768fc4d Mon Sep 17 00:00:00 2001 From: Dimitri Alston Date: Wed, 5 Jul 2023 16:42:14 -0400 Subject: [PATCH 1/7] Update documentation Replaced images of equations with math blocks. Added interval brand-and-bound example. Added quasiconvex example. Updated the favicon asset and some documentation formatting. --- .gitignore | 1 + docs/make.jl | 7 +- docs/src/assets/favicon.ico | Bin 64886 -> 16958 bytes docs/src/dev/contributing.md | 6 +- docs/src/dev/future.md | 2 +- docs/src/index.md | 6 +- docs/src/mccormick/operators.md | 21 +-- docs/src/mccormick/overview.md | 3 +- docs/src/mccormick/type.md | 7 +- docs/src/mccormick/usage.md | 51 +++--- docs/src/optimizer/bnb_back.md | 11 +- docs/src/optimizer/domain_reduction.md | 16 +- docs/src/optimizer/high_performance.md | 25 +-- docs/src/optimizer/optimizer.md | 19 +- docs/src/optimizer/relax_back.md | 7 +- docs/src/optimizer/udf_utilities.md | 6 +- docs/src/quick_start/alpha_bb.md | 71 ++++---- docs/src/quick_start/ex2.md | 1 - docs/src/quick_start/explicit_ann.md | 47 ++--- docs/src/quick_start/guidelines.md | 114 ++---------- docs/src/quick_start/interval_bb.md | 140 +++++++++++++++ docs/src/quick_start/qc_Equation_1.png | Bin 13854 -> 0 bytes docs/src/quick_start/qc_Equation_2.png | Bin 3968 -> 0 bytes docs/src/quick_start/qc_Equation_3.png | Bin 6300 -> 0 bytes docs/src/quick_start/qs_landing.md | 19 +- docs/src/quick_start/quasiconvex.md | 180 ++++++++++++------- docs/src/semiinfinite/SIPProbFormulation.png | Bin 21285 -> 0 bytes docs/src/semiinfinite/SIPformulation.png | Bin 26666 -> 0 bytes docs/src/semiinfinite/semiinfinite.md | 26 ++- src/eago_optimizer/types/extension.jl | 2 +- src/eago_optimizer/types/global_optimizer.jl | 2 +- 31 files changed, 424 insertions(+), 366 deletions(-) delete mode 100644 docs/src/quick_start/ex2.md create mode 100644 docs/src/quick_start/interval_bb.md delete mode 100644 docs/src/quick_start/qc_Equation_1.png delete mode 100644 docs/src/quick_start/qc_Equation_2.png delete mode 100644 docs/src/quick_start/qc_Equation_3.png delete mode 100644 docs/src/semiinfinite/SIPProbFormulation.png delete mode 100644 docs/src/semiinfinite/SIPformulation.png diff --git a/.gitignore b/.gitignore index 9f0ea459..e4634270 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *.mem *.cov docs/build/ +.vscode \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index 98aeddb4..e8cf2c0b 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -7,9 +7,9 @@ import McCormick: final_cut, mid3v, precond_and_contract!, AbstractMCCallback, p dline_seg, correct_exp!, cut, mid_grad, preconditioner_storage, newton, secant, MCCallback, contract!, affine_exp! -import EAGO: ExtensionType, Evaluator, variable_dbbt!, set_current_node!, +import EAGO: ExtensionType, Evaluator, variable_dbbt!, VariableInfo, Log, aggressive_filtering!, - bool_indx_diff, trivial_filtering!, SIPResult, SIPProblem, + bool_indx_diff!, trivial_filtering!, SIPResult, SIPProblem, GlobalOptimizer, InputProblem, ParsedProblem, is_integer_feasible_relaxed, local_problem_status, default_upper_heuristic, label_branch_variables!, label_fixed_variables!, AbstractDirectedGraph, AbstractCache, @@ -28,6 +28,7 @@ makedocs(modules = [EAGO, McCormick], prettyurls = get(ENV, "CI", nothing) == "true", canonical = "https://PSORLab.github.io/EAGO.jl/stable/", collapselevel = 1, + assets = ["assets/favicon.ico"] ), authors = "Matthew Wilhelm, Robert Gottlieb, Dimitri Alston, and Matthew Stuber", sitename = "EAGO.jl", @@ -35,7 +36,7 @@ makedocs(modules = [EAGO, McCormick], "Quick Start" => Any["quick_start/qs_landing.md", "quick_start/guidelines.md", "quick_start/explicit_ann.md", - "quick_start/ex2.md", + "quick_start/interval_bb.md", "quick_start/quasiconvex.md", "quick_start/alpha_bb.md" ], diff --git a/docs/src/assets/favicon.ico b/docs/src/assets/favicon.ico index 68821591f3c1033400c6e0a0d3dd821c2b4672d9..dcdda6ff272d589583dbe37a6f9cda0147873e8f 100644 GIT binary patch literal 16958 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 literal 64886 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%0Ay{ z=j4#RFu6?WJUWs7ERWDjfB=fC||iO^qco; z$rU-K!4E#>7&~v1b+{et6*R8))~5M#elMN}wrThXf>TSx$6bR7d;vY(tMo1vc)ca_ z+6o_*m*E@X3lC3eUVgloQ9g3sR9@trEze9mv7+Ofi$?qe&p2

(tJ+-#eMT{6vXg z%qabKjW$ooALY}k=Q`)OW!|_SHkH`_TZX`d$fX z9Pf=}?GKQP+&}%Pxn%SmSAt%`xeoAwNJT%k3CueD1!;2jckOWTx~8Dbk97 z3PippQ-OQD42S6lsi_=Ow8>P4K#r4uR4$#TKWE$#b&FF4NG|?obljVK;`uTNDc4tw zw~FTr-1T02EM%RvOpW6h&Yu8!g+Kj+_y?2}o07;wd>PJnq~IT%e-*(#Y^O>+ z$595Oji;xybPdH1AQ0ofMV#`cGUzj9=<)x=Jw`H9hGXmpIeA#miKi z@Q|KtLClXBh~;%4PWK3xhnUhm>?wW%=M^Kx&H+a1GxAFaia2A(Vm;DyU zp@33;ewmt%$4S8*Y8!h3)!0WT9N7_1Mhau6=^sb_%8e| z#(JW0SMaLwr7rph4JPtIE~O@cA8wCi#FY$5|De+kajLbN--X_Y^ZNrwm99&O)9v82 zN4l&`il0E7GFJ1WpwoCOoiDwdKHTCbNIpO6Beqv`nH=vxcA`GzxM+`by^B540bFmU V@PtDwiTCB>{Jdy?be(WN{XfPu6A}Ob diff --git a/docs/src/dev/contributing.md b/docs/src/dev/contributing.md index 91ab9a2c..2cd0aa95 100644 --- a/docs/src/dev/contributing.md +++ b/docs/src/dev/contributing.md @@ -1,10 +1,8 @@ # How to Contribute -We're always happy to welcome work with additional collaborators and contributors. One -of the easy ways for newcomers to contribute is by adding additional relaxations. +We're always happy to welcome work with additional collaborators and contributors. One of the easy ways for newcomers to contribute is by adding additional McCormick relaxations. -If you have any requests for additional functionality, bug fixes, or comments, -please feel free to open a new issue using the GitHub [issue tracker](https://github.com/PSORLab/EAGO.jl/issues) or reach out to us. +If you have any requests for additional functionality, bug fixes, or comments, please feel free to open a new issue using the GitHub [issue tracker](https://github.com/PSORLab/EAGO.jl/issues) or reach out to us. ## Contact Us diff --git a/docs/src/dev/future.md b/docs/src/dev/future.md index 9f879d21..8a4a035a 100644 --- a/docs/src/dev/future.md +++ b/docs/src/dev/future.md @@ -12,7 +12,7 @@ ## Other Things on the Wishlist (But Not Actively Being Worked On) * Implement the interval constraint propagation scheme presented in Vu 2008. For improved convergences. -* A parametric bisection routine will be updated that can divide the `(X,P)` space into a series of boxes that all contain unique branches of the implicit function `p->y(p)`. +* A parametric bisection routine will be updated that can divide the ``(X, P)`` space into a series of boxes that all contain unique branches of the implicit function ``p -> y(p)``. * Provide a better interface the nonconvex semi-infinite programs solvers (JuMPeR extension?). * Add additional McCormick relaxations. * Add handling for domain reduction of special expression forms. diff --git a/docs/src/index.md b/docs/src/index.md index 6c081b52..c1946b61 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -21,8 +21,7 @@ EAGO is a global and robust optimization platform based on McCormick relaxations ## Installing EAGO -EAGO is a registered Julia package and it can be installed using the Julia package manager. -From the Julia REPL, type `]` to enter the Package manager (Pkg) mode and run the following command: +EAGO is a registered Julia package and it can be installed using the Julia package manager. From the Julia REPL, type `]` to enter the Package manager (Pkg) mode and run the following command: ```jldoctest pkg> add EAGO @@ -34,8 +33,7 @@ Currently, EAGO is compatible with version 1.12 of JuMP. This allows a replicati pkg> add JuMP ``` -EAGO v0.8.1 is the current tagged version and requires Julia 1.6+ for full functionality (however Julia 1.0+ versions support partial functionality). Use with version 1.8 is recommended as the majority of in-house testing has occurred using this version of Julia. The user is directed to the [High-Performance Configuration](https://psorlab.github.io/EAGO.jl/optimizer/high_performance/) for instructions on how to install a high performance version of EAGO (rather than the basic entirely open-source version). -If any issues are encountered when loading EAGO (or when using it), please submit an issue using the GitHub [issue tracker](https://github.com/PSORLab/EAGO.jl/issues). +EAGO v0.8.1 is the current tagged version and requires Julia 1.6+ for full functionality (however Julia 1.0+ versions support partial functionality). Use with version 1.8 is recommended as the majority of in-house testing has occurred using this version of Julia. The user is directed to the [High-Performance Configuration](https://psorlab.github.io/EAGO.jl/optimizer/high_performance/) for instructions on how to install a high performance version of EAGO (rather than the basic entirely open-source version). If any issues are encountered when loading EAGO (or when using it), please submit an issue using the GitHub [issue tracker](https://github.com/PSORLab/EAGO.jl/issues). ## Examples diff --git a/docs/src/mccormick/operators.md b/docs/src/mccormick/operators.md index cde3972b..c277c973 100644 --- a/docs/src/mccormick/operators.md +++ b/docs/src/mccormick/operators.md @@ -1,10 +1,6 @@ # Currently Supported Operators -The operators currently supported are listed below. The operators with a check box -have been subject to a large degree of scrutiny and have been implemented for -both forward and reverse McCormick relaxations ([Wechsung2015](https://link.springer.com/article/10.1007/s10898-015-0303-6)). Each McCormick object is associated with a -parameter `T <: RelaxTag` which is either `NS` for nonsmooth relaxations ([Mitsos2009](https://epubs.siam.org/doi/abs/10.1137/080717341), [Scott2011](https://link.springer.com/article/10.1007/s10898-011-9664-7)), `MV` for multivariate relaxations ([Tsoukalas2014](https://link.springer.com/article/10.1007/s10898-014-0176-0), [Najman2017](https://link.springer.com/article/10.1007/s10898-016-0470-0)), -or `Diff` for differentiable relaxations ([Khan2016](https://link.springer.com/article/10.1007/s10898-016-0440-6), [Khan2018](https://link.springer.com/article/10.1007/s10898-017-0601-2), [Khan2019](https://www.tandfonline.com/doi/abs/10.1080/02331934.2018.1534108)). Conversion between `NS`, `MV`, and `Diff` relax tags is not currently supported. Convex and concave envelopes are used to compute relaxations of univariate functions. +The operators currently supported are listed below. The operators with a check box have been subject to a large degree of scrutiny and have been implemented for both forward and reverse McCormick relaxations ([Wechsung2015](https://link.springer.com/article/10.1007/s10898-015-0303-6)). Each McCormick object is associated with a parameter `T <: RelaxTag` which is either `NS` for nonsmooth relaxations ([Mitsos2009](https://epubs.siam.org/doi/abs/10.1137/080717341), [Scott2011](https://link.springer.com/article/10.1007/s10898-011-9664-7)), `MV` for multivariate relaxations ([Tsoukalas2014](https://link.springer.com/article/10.1007/s10898-014-0176-0), [Najman2017](https://link.springer.com/article/10.1007/s10898-016-0470-0)), or `Diff` for differentiable relaxations ([Khan2016](https://link.springer.com/article/10.1007/s10898-016-0440-6), [Khan2018](https://link.springer.com/article/10.1007/s10898-017-0601-2), [Khan2019](https://www.tandfonline.com/doi/abs/10.1080/02331934.2018.1534108)). Conversion between `NS`, `MV`, and `Diff` relax tags is not currently supported. Convex and concave envelopes are used to compute relaxations of univariate functions. ## Univariate McCormick Operators @@ -30,7 +26,7 @@ Both nonsmooth and Whitney-1 (once differentiable) relaxations are supported for ## Bivariate McCormick Operators -The following bivariate operators are supported for two [`MC`](@ref) objects. Both nonsmooth and Whitney-1 (once differentiable) relaxations are supported. +The following bivariate operators are supported for two [`MC`](@ref McCormick.MC) objects. Both nonsmooth and Whitney-1 (once differentiable) relaxations are supported. - **Multiplication** (`*`) - **Division** (`/`) @@ -44,9 +40,8 @@ Arbitrarily differentiable relaxations can be constructed for the following oper ## Common Subexpressions -The following functions can be used in place of common subexpressions encountered -in optimization and will result in improved performance (in each case, the standard -McCormick composition rules are often more expansive). +The following functions can be used in place of common subexpressions encountered in optimization and will result in improved performance (in each case, the standard McCormick composition rules are often more expansive). + ```@docs xexpax arh @@ -56,12 +51,8 @@ mm ## Bound Setting Functions -The following functions are used to specify that known bounds on a subexpression -exist and that the relaxation/interval bounds propagated should make use of this -information. The utility functions can be helpful in avoiding domain violations -that arise due to the overly expansive nature of composite relaxations. Improper use -of these functions may lead to cases in which the resulting relaxations are empty, -so the user is encouraged to use discretion. +The following functions are used to specify that known bounds on a subexpression exist and that the relaxation/interval bounds propagated should make use of this information. The utility functions can be helpful in avoiding domain violations that arise due to the overly expansive nature of composite relaxations. Improper use of these functions may lead to cases in which the resulting relaxations are empty, so the user is encouraged to use discretion. + ```@docs positive negative diff --git a/docs/src/mccormick/overview.md b/docs/src/mccormick/overview.md index 37a224f1..18ead566 100644 --- a/docs/src/mccormick/overview.md +++ b/docs/src/mccormick/overview.md @@ -1,7 +1,6 @@ # Overview -EAGO provides a library of McCormick relaxations in native Julia code. The EAGO optimizer supports -relaxing functions using **nonsmooth McCormick relaxations** ([Mitsos2009](https://epubs.siam.org/doi/abs/10.1137/080717341), [Scott2011](https://link.springer.com/article/10.1007/s10898-011-9664-7)), **smooth McCormick relaxations** ([Khan2016](https://link.springer.com/article/10.1007/s10898-016-0440-6), [Khan2018](https://link.springer.com/article/10.1007/s10898-017-0601-2), [Khan2019](https://www.tandfonline.com/doi/abs/10.1080/02331934.2018.1534108)), and **multi-variant McCormick relaxations** ([Tsoukalas2014](https://link.springer.com/article/10.1007/s10898-014-0176-0); a variant of **subgradient-based interval refinement** ([Najman2017](https://link.springer.com/article/10.1007/s10898-016-0470-0))). For functions with arbitrarily differentiable relaxations, the differentiable constant μ can be modified by adjusting a constant value in the package. Additionally, validated and nonvalidated interval bounds are supported via [IntervalArithmetic.jl](https://github.com/JuliaIntervals/IntervalArithmetic.jl) which is reexported. The basic McCormick operator and reverse McCormick operator ([Wechsung2015](https://link.springer.com/article/10.1007/s10898-015-0303-6)) libraries are included in two dependent subpackages which can loaded and used independently: +EAGO provides a library of McCormick relaxations in native Julia code. The EAGO optimizer supports relaxing functions using **nonsmooth McCormick relaxations** ([Mitsos2009](https://epubs.siam.org/doi/abs/10.1137/080717341), [Scott2011](https://link.springer.com/article/10.1007/s10898-011-9664-7)), **smooth McCormick relaxations** ([Khan2016](https://link.springer.com/article/10.1007/s10898-016-0440-6), [Khan2018](https://link.springer.com/article/10.1007/s10898-017-0601-2), [Khan2019](https://www.tandfonline.com/doi/abs/10.1080/02331934.2018.1534108)), and **multi-variant McCormick relaxations** ([Tsoukalas2014](https://link.springer.com/article/10.1007/s10898-014-0176-0); a variant of **subgradient-based interval refinement** ([Najman2017](https://link.springer.com/article/10.1007/s10898-016-0470-0))). For functions with arbitrarily differentiable relaxations, the differentiable constant μ can be modified by adjusting a constant value in the package. Additionally, validated and nonvalidated interval bounds are supported via [IntervalArithmetic.jl](https://github.com/JuliaIntervals/IntervalArithmetic.jl) which is reexported. The basic McCormick operator and reverse McCormick operator ([Wechsung2015](https://link.springer.com/article/10.1007/s10898-015-0303-6)) libraries are included in two dependent subpackages which can loaded and used independently: - [McCormick.jl](https://github.com/PSORLab/McCormick.jl): A library of forward-mode and implicit McCormick operators. - [ReverseMcCormick.jl](https://github.com/PSORLab/ReverseMcCormick.jl): A reverse-mode McCormick operator library. diff --git a/docs/src/mccormick/type.md b/docs/src/mccormick/type.md index 9d356da1..32c2de35 100644 --- a/docs/src/mccormick/type.md +++ b/docs/src/mccormick/type.md @@ -1,7 +1,7 @@ # Types ```@docs -MC +McCormick.MC McCormick.RelaxTag ``` @@ -28,10 +28,7 @@ McCormick.golden_section ## (Under Development) MCNoGrad -A handful of applications make use of McCormick relaxations directly without the need for subgradients. We -are currently adding support for a McCormick `struct` which omits subgradient propagation in favor of return -a MCNoGrad object and associated derivative information. This is currently under development and likely -lacking key functionality. +A handful of applications make use of McCormick relaxations directly without the need for subgradients. We are currently adding support for a McCormick `struct` which omits subgradient propagation in favor of return a MCNoGrad object and associated derivative information. This is currently under development and likely lacking key functionality. ```@docs McCormick.MCNoGrad diff --git a/docs/src/mccormick/usage.md b/docs/src/mccormick/usage.md index 79c70104..c1e62aec 100644 --- a/docs/src/mccormick/usage.md +++ b/docs/src/mccormick/usage.md @@ -1,29 +1,26 @@ # Basic Usage -## Bounding a Function via McCormick Operators +## Bounding a Univariate Function -In order to bound a function using a McCormick relaxation, you first construct a -McCormick object (`x::MC`) that bounds the input variables, and then you pass these -variables to the desired function. +In order to bound a function using a McCormick relaxation, you first construct a McCormick object (`x::MC`) that bounds the input variables, and then you pass these variables to the desired function. -In the example below, convex/concave relaxations of the function `f(x) = x(x-5)sin(x)` -are calculated at `x = 2` on the interval `[1,4]`. +In the example below, convex/concave relaxations of the function ``f(x) = x (x - 5) \sin(x)`` are calculated at ``x = 2`` on the interval ``[1, 4]``. ```julia using McCormick -# Create MC object for x = 2.0 on [1.0,4.0] for relaxing +# Create MC object for x = 2.0 on [1.0, 4.0] for relaxing # a function f(x) on the interval Intv -f(x) = x*(x-5.0)*sin(x) +f(x) = x*(x - 5.0)*sin(x) x = 2.0 # Value of independent variable x -Intv = Interval(1.0,4.0) # Define interval to relax over +Intv = Interval(1.0, 4.0) # Define interval to relax over # Note that McCormick.jl reexports IntervalArithmetic.jl # and StaticArrays. So no using statement for these is # necessary. # Create McCormick object -xMC = MC{1,NS}(x,Intv,1) +xMC = MC{1,NS}(x, Intv, 1) fMC = f(xMC) # Relax the function @@ -34,40 +31,44 @@ ccgrad = fMC.cc_grad # Subgradient/gradient of concave relaxation Iv = fMC.Intv # Retrieve interval bounds of f(x) on Intv ``` -By plotting the results we can easily visualize the convex and concave -relaxations, interval bounds, and affine bounds constructed using the subgradient -at the middle of X. +By plotting the results we can easily visualize the convex and concave relaxations, interval bounds, and affine bounds constructed using the subgradient at the middle of ``X``. ![Figure_1](Figure_1.png) -If we instead use the constructor `xMC = MC{1,Diff}(x,Intv,1)` in the above code and re-plot, -we arrive at the following graph. Note that these relaxations are differentiable, but not as -tight as the nonsmooth relaxations. +If we instead use the constructor `xMC = MC{1,Diff}(x, Intv, 1)` in the above code and re-plot, we arrive at the following graph. Note that these relaxations are differentiable, but not as tight as the nonsmooth relaxations. ![Figure_2](Figure_2.png) -This can readily be extended to multivariate functions, for example, `f(x,y) = (4 - 2.1x^2 + (x^4)/6)x^2 + xy + (-4 + 4y^2)y^2`: +## Bounding a Multivariate Function + +This can readily be extended to multivariate functions, for example: + +```math +\begin{aligned} +f(x,y) = \big(4 - 2.1 x^{2} + \frac{x^{4}}{6} \big) x^{2} + x y + (-4 + 4 y^{2}) y^{2} +\end{aligned} +``` ```julia using McCormick # Define function -f(x,y) = (4.0 - 2.1*x^2 + (x^4)/6.0)*x^2 + x*y + (-4.0 + 4.0*y^2)*y^2 +f(x, y) = (4.0 - 2.1*x^2 + (x^4)/6.0)*x^2 + x*y + (-4.0 + 4.0*y^2)*y^2 # Define intervals for independent variables n = 30 X = Interval{Float64}(-2,0) -Y = Interval{Float64}(-0.5,0.5) -xrange = range(X.lo,stop=X.hi,length=n) -yrange = range(Y.lo,stop=Y.hi,length=n) +Y = Interval{Float64}(-0.5, 0.5) +xrange = range(X.lo, stop=X.hi, length=n) +yrange = range(Y.lo, stop=Y.hi, length=n) # Calculate differentiable McCormick relaxation for (i,x) in enumerate(xrange) for (j,y) in enumerate(yrange) - z = f(x,y) # Calculate function values - xMC = MC{1,Diff}(x,X,1) # Differentiable relaxation for x - yMC = MC{1,Diff}(y,Y,2) # Differentiable relaxation for y - fMC = f(xMC,yMC) # Relax the function + z = f(x, y) # Calculate function values + xMC = MC{1,Diff}(x, X, 1) # Differentiable relaxation for x + yMC = MC{1,Diff}(y, Y, 2) # Differentiable relaxation for y + fMC = f(xMC, yMC) # Relax the function cv = fMC.cv # Convex relaxation cc = fMC.cc # Concave relaxation end diff --git a/docs/src/optimizer/bnb_back.md b/docs/src/optimizer/bnb_back.md index 7dc9fb71..5fb91556 100644 --- a/docs/src/optimizer/bnb_back.md +++ b/docs/src/optimizer/bnb_back.md @@ -1,7 +1,6 @@ # EAGO's Branch and Bound Routine -This component is meant to provide a flexible framework for implementing spatial branch-and-bound based optimization routines in Julia. -All components of the branch-and-bound routine can be customized by the individual user: lower bounding problem, upper bounding problem. +This component is meant to provide a flexible framework for implementing spatial branch-and-bound based optimization routines in Julia. All components of the branch-and-bound routine can be customized by the individual user: lower-bounding problem, upper-bounding problem. ## Branch and Bound Node Storage @@ -9,7 +8,7 @@ All components of the branch-and-bound routine can be customized by the individu EAGO.NodeBB ``` -The global optimizer structure holds all information relevant to branch-and-bound. +The `GlobalOptimizer` structure holds all information relevant to branch-and-bound. ```@docs EAGO.GlobalOptimizer @@ -51,7 +50,7 @@ The global optimizer structure holds all information relevant to branch-and-boun EAGO.termination_check(t::ExtensionType, m::GlobalOptimizer) EAGO.upper_problem!(t::ExtensionType, m::GlobalOptimizer) EAGO.parse_global!(t::ExtensionType, m::GlobalOptimizer) - EAGO.optimize_hook!(t::ExtensionType, m::GlobalOptimizer) + EAGO.optimize_hook!(t::ExtensionType, m::Optimizer) ``` ## Internal Subroutines @@ -59,7 +58,7 @@ The global optimizer structure holds all information relevant to branch-and-boun ```@docs EAGO.is_integer_subproblem(m) EAGO.is_integer_feasible_local(m::GlobalOptimizer, d) -│ EAGO.is_integer_feasible_relaxed(m::GlobalOptimizer) + EAGO.is_integer_feasible_relaxed(m::GlobalOptimizer) EAGO.interval_bound EAGO.lower_interval_bound EAGO.same_box(x::NodeBB,y::NodeBB, atol::Float64) @@ -71,7 +70,7 @@ The global optimizer structure holds all information relevant to branch-and-boun EAGO.label_branch_variables!(m::GlobalOptimizer) EAGO.add_nonlinear!(m::GlobalOptimizer) EAGO.parse_classify_problem!(m::GlobalOptimizer) - EAGO.local_problem_status!(t::MathOptInterface.TerminationStatusCode, r::MathOptInterface.ResultStatusCode) + EAGO.local_problem_status(t::MathOptInterface.TerminationStatusCode, r::MathOptInterface.ResultStatusCode) ``` ## Functions for Generating Console Output diff --git a/docs/src/optimizer/domain_reduction.md b/docs/src/optimizer/domain_reduction.md index fb8fc173..8e113187 100644 --- a/docs/src/optimizer/domain_reduction.md +++ b/docs/src/optimizer/domain_reduction.md @@ -10,8 +10,7 @@ variable_dbbt! ## Special Forms -Bound tightening for linear forms, univariate quadratic forms, and -bivariate quadratic forms are also supported. +Bound tightening for linear forms, univariate quadratic forms, and bivariate quadratic forms are also supported. ```@docs EAGO.fbbt! @@ -19,10 +18,7 @@ EAGO.fbbt! ## Constraint Propagation -EAGO contains a constraint propagation architecture that supported forward and -reverse evaluation of set-valued functions on the directed acyclic graph. -The interval contractor and reverse McCormick relaxation-based contractors are -currently available. +EAGO contains a constraint propagation architecture that supported forward and reverse evaluation of set-valued functions on the directed acyclic graph. The interval contractor and reverse McCormick relaxation-based contractors are currently available. ```@docs EAGO.set_constraint_propagation_fbbt! @@ -30,9 +26,7 @@ EAGO.set_constraint_propagation_fbbt! ## Optimization-Based Bound Tightening -EAGO makes use of an optimization-based bound tightening scheme using filtering -and greedy ordering as detailed in: Gleixner, A.M., Berthold, T., Müller, B. -et al. J Glob Optim (2017) 67: 731. [https://doi.org/10.1007/s10898-016-0450-](https://doi.org/10.1007/s10898-016-0450-4). +EAGO makes use of an optimization-based bound tightening scheme using filtering and greedy ordering as detailed in [[1](#References)]. ```@docs EAGO.obbt! @@ -40,3 +34,7 @@ EAGO.trivial_filtering!(m::GlobalOptimizer{R,S,Q}, n::NodeBB) where {R,S,Q<:Exte EAGO.aggressive_filtering!(m::GlobalOptimizer{R,S,Q}, n::NodeBB) where {R,S,Q<:ExtensionType} EAGO.bool_indx_diff!(z::Vector{Bool},x::Vector{Bool}, y::Vector{Bool}) ``` + +## References + +1. Gleixner, A.M., Berthold, T., Müller, B. et al. J Glob Optim (2017) 67: 731. [https://doi.org/10.1007/s10898-016-0450-4](https://doi.org/10.1007/s10898-016-0450-4) diff --git a/docs/src/optimizer/high_performance.md b/docs/src/optimizer/high_performance.md index bf534e27..2c916b1d 100644 --- a/docs/src/optimizer/high_performance.md +++ b/docs/src/optimizer/high_performance.md @@ -1,31 +1,20 @@ # High-Performance Configuration -## LP Solver Selection +## Linear Programming Solver Selection -By default, EAGO uses GLPK for solving linear subproblems introduced. Using a -commercial linear solver is highly recommended such as Gurobi, CPLEX, or XPRESS -is highly recommended. Both Gurobi and CPLEX are free for academics and -installation information can be found on the [Gurobi website](http://www.gurobi.com/academia/academia-center) and the [IBM website](https://www.ibm.com/developerworks/community/blogs/jfp/entry/CPLEX_Is_Free_For_Students?lang=en), respectively. +By default, EAGO uses GLPK for solving linear subproblems introduced. Using a commercial linear programming (LP) solver is highly recommended, such as Gurobi, CPLEX, or XPRESS. Both Gurobi and CPLEX are free for academics and installation information can be found on the [Gurobi website](http://www.gurobi.com/academia/academia-center) and the [IBM website](https://www.ibm.com/developerworks/community/blogs/jfp/entry/CPLEX_Is_Free_For_Students?lang=en), respectively. A non-default LP solver can then be selected by the user via a series of keyword argument inputs as illustrated in the code snippet below. The `relaxed_optimizer` contains an instance optimizer with valid relaxations that are made at the root node and is updated with affine relaxations in place. ```julia # Create opt EAGO Optimizer with Gurobi as a lower subsolver -subsolver_config = SubSolvers(relaxed_optimizer = Gurobi.Optimizer(OutputFlag=0)) -eago_factory = () -> EAGO.Optimizer(subsolvers = subsolver_config) +eago_factory = () -> EAGO.Optimizer(SubSolvers(; r = Gurobi.Optimizer())) m = Model(eago_factory) ``` ## Rounding Mode -The [IntervalArithmetic.jl](https://github.com/JuliaIntervals/IntervalArithmetic.jl) package supports a number of different directed rounding -modes. The default directed rounding mode is `:tight`. It is recommended that the -user specify that `:accurate` directed rounding mode be used as it may results -in a significant performance improvement. Setting a rounding mode can requires -the redefinition of a number of functions. As a result, this should only be done -at the top-level by the user (rather than by using keyword arguments). To set the -rounding mode to `:accurate` using the following syntax when loading the EAGO package -initially: +The [IntervalArithmetic.jl](https://github.com/JuliaIntervals/IntervalArithmetic.jl) package supports a number of different directed rounding modes. The default directed rounding mode is `:tight`. It is recommended that the user specify that `:accurate` directed rounding mode be used as it may results in a significant performance improvement. Setting a rounding mode can requires the redefinition of a number of functions. As a result, this should only be done at the top-level by the user (rather than by using keyword arguments). To set the rounding mode to `:accurate` using the following syntax when loading the EAGO package initially: ```julia using IntervalArithmetic; setrounding(Interval, :accurate) @@ -35,11 +24,7 @@ using EAGO ## Ipopt Build -Ipopt is the recommended solver for upper bounding problems. Ipopt's performance is highly -dependent on the linear algebra package used (up to 30x). By default MUMPS is used. -It is recommended that you either compile Ipopt with HSL MA57 or the Pardiso linear -algebra packages with a machine specific Blas library (for Intel users the JuliaPro -MKL version is recommended). For information on this, see the below links: +Ipopt is the recommended solver for upper-bounding problems. Ipopt's performance is highly dependent on the linear algebra package used (up to 30x). By default MUMPS is used. It is recommended that you either compile Ipopt with HSL MA57 or the Pardiso linear algebra packages with a machine specific Blas library (for Intel users the JuliaPro MKL version is recommended). For information on this, see the links below: - [Compiling Ipopt](https://www.coin-or.org/Ipopt/documentation/node13.html) - Julia specifics: diff --git a/docs/src/optimizer/optimizer.md b/docs/src/optimizer/optimizer.md index 70bed03b..aa80ac4a 100644 --- a/docs/src/optimizer/optimizer.md +++ b/docs/src/optimizer/optimizer.md @@ -1,7 +1,6 @@ # EAGO Optimizer -The `EAGO.Optimizer` object holds all algorithm solution information. A description -of all user-facing options has been provided in the docstring. +The `Optimizer` object holds all algorithm solution information. A description of all user-facing options has been provided in the docstring. ## EAGO.Optimizer @@ -11,9 +10,7 @@ Optimizer ## EAGO Specific Functions and Operators -EAGO supports a number of functions and operators that for which specialized relaxation -routines are available. These can be registered and added to a JuMP model using the -function +EAGO supports a number of functions and operators that for which specialized relaxation routines are available. These can be registered and added to a JuMP model using the function: ```@docs EAGO.register_eago_operators!(m::JuMP.Model) @@ -47,14 +44,4 @@ EAGO.initial_parse!(m::Optimizer{R,S,T}) where {R,S,T} ## Extending EAGO -Functionality has been included that allows for extension's to EAGO's optimizer -to readily be defined. This can be done in two ways first defining a new structure -which is a subtype of `EAGO.ExtensionType` and overloading methods associated with -this new structure. An instance of this new structure is provided to the `EAGO.Optimizer` -using the `ext_type` keyword. This results in EAGO now dispatch to the new -methods rather than the generally defined methods for the parent type. For a complete -example, the reader is directed to the [interval bounding example](https://github.com/PSORLab/EAGO-notebooks/blob/master/notebooks/nlpopt_interval_bnb.ipynb) and [quasiconvex example](https://github.com/PSORLab/EAGO-notebooks/blob/master/notebooks/custom_quasiconvex.ipynb). Alternatively, the user can overload the `optimize_hook!` for -this subtype which will entirely circumvent the default global solution routine. Additional -information can be stored in the `ext` field of EAGO. In order to allow for compatibility -between packages the user is encouraged to append their extension name to the start of each -variable name (e.g. `newext_newdata`). +Functionality has been included that allows for extensions to EAGO's [`Optimizer`](@ref) to be readily defined. This can be done in two ways first defining a new structure which is a subtype of [`ExtensionType`](@ref) and overloading methods associated with this new structure. An instance of this new structure is provided to the [`Optimizer`](@ref) using the `ext_type` keyword. This results in EAGO now dispatch to the new methods rather than the generally defined methods for the parent type. For a complete example, the reader is directed to the [interval bounding example](@ref "Standard-Use Example 2") and the [quasiconvex example](@ref "Advanced-Use Example 1"). Alternatively, the user can overload the `optimize_hook!` for this subtype which will entirely circumvent the default global solution routine. Additional information can be stored in the `ext` field of the [`Optimizer`](@ref). In order to allow for compatibility between packages the user is encouraged to append their extension name to the start of each variable name (e.g. `newext_newdata`). diff --git a/docs/src/optimizer/relax_back.md b/docs/src/optimizer/relax_back.md index 9e6d5cba..f9f73e32 100644 --- a/docs/src/optimizer/relax_back.md +++ b/docs/src/optimizer/relax_back.md @@ -24,8 +24,7 @@ EAGO organizes information associated with each node in a given graph structure EAGO.initialize!(::AbstractCache, ::AbstractDirectedGraph) ``` -Information in a given `EAGO.AbstractCache` is populated by performing a series of forward and reverse passes of the graph structure which dispatch off of an -`EAGO.AbstractCacheAttribute` which indicates what particular information is desired. +Information in a given `EAGO.AbstractCache` is populated by performing a series of forward and reverse passes of the graph structure which dispatch off of an `EAGO.AbstractCacheAttribute` which indicates what particular information is desired. ```@docs EAGO.AbstractCacheAttribute @@ -58,9 +57,7 @@ The forward and reverse routines are overloaded as follows: EAGO.rprop!(t::AbstractCacheAttribute, v::Constant, g::AbstractDirectedGraph, c::AbstractCache, k::Int) ``` -Forward and reverse subroutines are overloaded for individual operators using through functions of the forms -`fprop!(t::AbstractCacheAttribute, v::Val{AtomType}, g::AbstractDirectedGraph, b::AbstractCache, k::Int)` and -`rprop!(t::AbstractCacheAttribute, v::Val{AtomType}, g::AbstractDirectedGraph, b::AbstractCache, k::Int)`. +Forward and reverse subroutines are overloaded for individual operators using through functions of the forms `fprop!(t::AbstractCacheAttribute, v::Val{AtomType}, g::AbstractDirectedGraph, b::AbstractCache, k::Int)` and `rprop!(t::AbstractCacheAttribute, v::Val{AtomType}, g::AbstractDirectedGraph, b::AbstractCache, k::Int)`. ## Other Routines diff --git a/docs/src/optimizer/udf_utilities.md b/docs/src/optimizer/udf_utilities.md index 54ad3234..5b0bc053 100644 --- a/docs/src/optimizer/udf_utilities.md +++ b/docs/src/optimizer/udf_utilities.md @@ -1,8 +1,6 @@ -# User-Defined Functions (UDFs) and Directed Acyclic Graph (DAG) Utilities +# User-Defined Functions and Directed Acyclic Graph Utilities -EAGO has included basic functionality to manipulate user-defined functions. -These features are largely experimental and we're interested in providing -additional for novel use cases. +EAGO has included basic functionality to manipulate user-defined functions (UDFs). EAGO also has utilities for directed acyclic graphs (DAGs). These features are largely experimental and we're interested in providing additional features for novel use cases. ## DAG Substitution and Flattening diff --git a/docs/src/quick_start/alpha_bb.md b/docs/src/quick_start/alpha_bb.md index 882002dd..b02bac61 100644 --- a/docs/src/quick_start/alpha_bb.md +++ b/docs/src/quick_start/alpha_bb.md @@ -8,9 +8,9 @@ In this example, we will demonstrate the use of a user-defined lower-bounding pr ```math \begin{aligned} -&\min_{\mathbf x\in\mathbb R^2}\frac{1}{2}\mathbf x^{\rm T}\mathbf Q_f\mathbf x+\mathbf c_f^{\rm T}\mathbf x\\ -{\rm s.t.}\;\;&g_1(\mathbf x)=\frac{1}{2}\mathbf x^{\rm T}\mathbf Q_{g_1}\mathbf x+\mathbf c_{g_1}^{\rm T}\mathbf x\le 0\\ -&g_2(\mathbf x)=\frac{1}{2}\mathbf x^{\rm T}\mathbf Q_{g_2}\mathbf x+\mathbf c_{g_2}^{\rm T}\mathbf x\le 0\\ +& \min_{\mathbf x \in \mathbb R^{2}} \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{f} \mathbf x + \mathbf c_{f}^{\rm T} \mathbf x\\ +{\rm s.t.} \;\; & g_{1}(\mathbf x)= \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{g_{1}}\mathbf x + \mathbf c_{g_{1}}^{\rm T} \mathbf x \leq 0\\ +& g_{2}(\mathbf x) = \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{g_{2}} \mathbf x + \mathbf c_{g_{2}}^{\rm T} \mathbf x \leq 0\\ \end{aligned} ``` @@ -27,26 +27,26 @@ For convenience, we'll define the following function that returns all the proble ```julia function QCQP_setup() - Qf = [3. 3/2.;3/2. -5.] - cf = [3.;2.] + Qf = [3.0, 3/2; 3/2, -5.0] + cf = [3.0; 2.0] - Qg1 = [-2. 5.;5. -2.] - cg1 = [1.;3.] + Qg1 = [-2.0, 5.0; 5.0, -2.0] + cg1 = [1.0; 3.0] - Qg2 = [-6. 3.;3. 2.] - cg2 = [2.;1.] + Qg2 = [-6.0, 3.0; 3.0, 2.0] + cg2 = [2.0; 1.0] - return Qf,cf,Qg1,cg1,Qg2,cg2 + return Qf, cf, Qg1, cg1, Qg2, cg2 end ``` -The next function we'll define will take as input data for a particular quadratic function and the interval bounds on the decision variables, and construct an ``\alpha``BB convex relaxation of that function. Since we're solving a QCQP, we'll use the `eigvals` function to directly compute the eigenvalues of the input ``\mathbf Q_i`` matrix. +The next function we'll define will take as input data for a particular quadratic function and the interval bounds on the decision variables, and construct an ``\alpha``BB convex relaxation of that function. Since we're solving a QCQP, we'll use the [`eigvals`](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.eigvals) function to directly compute the eigenvalues of the input ``\mathbf Q_i`` matrix. ```julia function αBB_relax(Q::Matrix{T}, c::Vector{T}, xL::Vector{T}, xU::Vector{T}, x::Real...) where {T<:Float64} - α = max(0,-minimum(eigvals(Q))/2) - y = [x[1];x[2]] - cv = 1/2*y'*Q*y+c'*y+α*(xL-y)'*(xU-y) + α = max(0.0, -minimum(eigvals(Q))/2) + y = [x[1]; x[2]] + cv = 1/2*y'*Q*y + c'*y + α*(xL - y)'*(xU - y) return cv end ``` @@ -67,30 +67,30 @@ function EAGO.lower_problem!(t::αBB_Convex, opt::GlobalOptimizer) xL = n.lower_variable_bounds[1:2] xU = n.upper_variable_bounds[1:2] # Get the problem data - Qf,cf,Qg1,cg1,Qg2,cg2=QCQP_setup() + Qf, cf, Qg1, cg1, Qg2, cg2 = QCQP_setup() # Define the JuMP model and declare the solver mL = JuMP.Model(JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol" => 1.0e-6, "print_level" => 0)) - @variable(mL,xL[i]<=x[i=1:2]<=xU[i]) + @variable(mL, xL[i] <= x[i=1:2] <= xU[i]) # Define the function closures for the user-defined relaxations - fcv(x...) = αBB_relax(Qf,cf,xL,xU,x...) - g1cv(x...) = αBB_relax(Qg1,cg1,xL,xU,x...) - g2cv(x...) = αBB_relax(Qg2,cg2,xL,xU,x...) + fcv(x...) = αBB_relax(Qf, cf, xL, xU, x...) + g1cv(x...) = αBB_relax(Qg1, cg1, xL, xU, x...) + g2cv(x...) = αBB_relax(Qg2, cg2, xL, xU, x...) # Register the user-defined functions - # Note: if the gradients and Hessians are directly available, they could + # Note: If the gradients and Hessians are directly available, they could # be passed as arguments to the register function to speed things up. - JuMP.register(mL,:fcv,2,fcv,autodiff=true) - JuMP.register(mL,:g1cv,2,g1cv,autodiff=true) - JuMP.register(mL,:g2cv,2,g2cv,autodiff=true) + JuMP.register(mL, :fcv, 2, fcv, autodiff=true) + JuMP.register(mL, :g1cv, 2, g1cv, autodiff=true) + JuMP.register(mL, :g2cv, 2, g2cv, autodiff=true) # Declare the objective function and constraints - @NLobjective(mL,Min,fcv(x[1],x[2])) - @NLconstraint(mL,g1cv(x[1],x[2])<=0.) - @NLconstraint(mL,g2cv(x[1],x[2])<=0.) + @NLobjective(mL, Min, fcv(x[1], x[2])) + @NLconstraint(mL, g1cv(x[1], x[2]) <= 0.0) + @NLconstraint(mL, g2cv(x[1], x[2]) <= 0.0) # Solve the relaxed problem JuMP.optimize!(mL) @@ -117,8 +117,7 @@ end !!! note - By default, EAGO solves the epigraph reformulation of your original problem, which increases the original problem dimensionality by +1 with the introduction of an auxiliary variable. When defining custom routines (such as the lower-bounding problem here) that are intended to work nicely with default EAGO routines (such as preprocessing), the user must account for the *new* dimensionality of the problem. In the code above, we wish to access the information of the specific B&B node and define an optimization problem based on that information. However, in this example, the node has information for 3 variables (the original 2 plus 1 for the auxiliary variable appended to the original variable vector) as ``(x_1,x_2,\eta)``. The lower-bounding problem was defined to optimize the relaxed problem with respect to the original 2 decision variables. When storing the results of this subproblem to the current B&B node, it is important to take care to store the information at the appropriate indices and not inadvertently redefine the problem dimensionality (i.e., by simply storing the optimization solution as the `lower_solution` of the current node). For problems that are defined to only branch on a subset of the original variables, the optimizer has a member `_sol_to_branch_map` that carries the mapping between the indices of the original variables to those of the variables being branched on. See the [Advanced-Use Example 1](@ref) to see how this is done. - + By default, EAGO solves the epigraph reformulation of your original problem, which increases the original problem dimensionality by +1 with the introduction of an auxiliary variable. When defining custom routines (such as the lower-bounding problem here) that are intended to work nicely with default EAGO routines (such as preprocessing), the user must account for the *new* dimensionality of the problem. In the code above, we wish to access the information of the specific B&B node and define an optimization problem based on that information. However, in this example, the node has information for 3 variables (the original 2 plus 1 for the auxiliary variable appended to the original variable vector) as ``(x_{1}, x_{2}, \eta)``. The lower-bounding problem was defined to optimize the relaxed problem with respect to the original 2 decision variables. When storing the results of this subproblem to the current B&B node, it is important to take care to store the information at the appropriate indices and not inadvertently redefine the problem dimensionality (i.e., by simply storing the optimization solution as the `lower_solution` of the current node). For problems that are defined to only branch on a subset of the original variables, the optimizer has a member `_sol_to_branch_map` that carries the mapping between the indices of the original variables to those of the variables being branched on. See the [Advanced-Use Example 1](@ref) to see how this is done. ## (Optional) Turn Off Processing Routines @@ -147,22 +146,22 @@ end Now, we'll tell EAGO to use our custom/extended solver, set up the main JuMP model, and solve it with our custom solver. ```julia -factory = () -> EAGO.Optimizer(SubSolvers(; t=αBB_Convex() )) +factory = () -> EAGO.Optimizer(SubSolvers(; t = αBB_Convex() )) m = JuMP.Model(optimizer_with_attributes(factory, "relative_tolerance" => 1e-3, "verbosity" => 1, "output_iterations" => 1, "branch_variable" => Bool[true; true], )) -Qf,cf,Qg1,cg1,Qg2,cg2=QCQP_setup() # Get QCQP data -xL = [-3.;-5.] # Lower bounds on x -xU = [1.; 2] # Upper bounds on x +Qf, cf, Qg1, cg1, Qg2, cg2 = QCQP_setup() # Get QCQP data +xL = [-3.0; -5.0] # Lower bounds on x +xU = [1.0; 2.0] # Upper bounds on x @variable(m, xL[i] <= x[i=1:2] <= xU[i]) # Define objective and constraints -@objective(m,Min,1/2*x'*Qf*x+cf'*x) -@constraint(m,1/2*x'*Qg1*x+cg1'*x<=0.) -@constraint(m,1/2*x'*Qg2*x+cg2'*x<=0.) +@objective(m, Min, 1/2*x'*Qf*x + cf'*x) +@constraint(m, 1/2*x'*Qg1*x + cg1'*x <= 0.0) +@constraint(m, 1/2*x'*Qg2*x + cg2'*x <= 0.0) # Solve the problem @time optimize!(m) @@ -170,7 +169,7 @@ xU = [1.; 2] # Upper bounds on x ## Retrieve Results -We then recover the objective value, the solution value, and termination status codes using standard JuMP syntax. +We then recover the objective value, the solution values, and termination status codes using standard JuMP syntax. ```julia println("x1* = ", JuMP.value(x[1]), " x2* = ", diff --git a/docs/src/quick_start/ex2.md b/docs/src/quick_start/ex2.md deleted file mode 100644 index 27a327e6..00000000 --- a/docs/src/quick_start/ex2.md +++ /dev/null @@ -1 +0,0 @@ -# Standard-Use Example 2 diff --git a/docs/src/quick_start/explicit_ann.md b/docs/src/quick_start/explicit_ann.md index 66313fed..909dd7bd 100644 --- a/docs/src/quick_start/explicit_ann.md +++ b/docs/src/quick_start/explicit_ann.md @@ -4,57 +4,50 @@ This example is also provided [here as a Jupyter Notebook](https://github.com/PS ### Solving an ANN to Optimality in EAGO -In [[1](#references),[2](#references)], a surrogate artificial neural network (ANN) model of bioreactor productivity was constructed by fitting results from computationally expensive computational fluid dynamics (CFD) simulations. -The authors then optimized this surrogate model to obtain ideal processing conditions. The optimization problem is given by: +In [[1](#References),[2](#References)], a surrogate artificial neural network (ANN) model of bioreactor productivity was constructed by fitting results from computationally expensive computational fluid dynamics (CFD) simulations. The authors then optimized this surrogate model to obtain ideal processing conditions. The optimization problem is given by: ```math \begin{aligned} -\max_{\mathbf x \in X} B_{2} + \sum_{r = 1}^{3} W_{2,r} \frac{2}{1 + \exp (-2y_{r} + B_{1,r})} \;\; \text{where} \;\; y_{r} = \sum_{i = 1}^{8} W_{1,ir} x_{i} +\max_{\mathbf x \in X} B_{2} + \sum_{r = 1}^{3} W_{2,r} \frac{2}{1 + \exp (-2y_{r} + B_{1,r})} \;\; {\rm where} \;\; y_{r} = \sum_{i = 1}^{8} W_{1,ir} x_{i} \end{aligned} ``` ## Input Parameters -In the first block, we input parameters values supplied in the paper for ``W_1``, ``W_2``, -``B_1``, and ``B_2`` into Julia as simple array objects. We also input bounds for the variables -which are used to scale the values obtained from optimization from ``[-1, 1]`` back into the -design values. +In the first block, we input parameters values supplied in the paper for ``W_1``, ``W_2``, ``B_1``, and ``B_2`` into Julia as simple array objects. We also input bounds for the variables which are used to scale the values obtained from optimization from ``[-1, 1]`` back into the design values. ```julia using JuMP, EAGO # Weights associated with the hidden layer -W1 = [ 0.54 -1.97 0.09 -2.14 1.01 -0.58 0.45 0.26; - -0.81 -0.74 0.63 -1.60 -0.56 -1.05 1.23 0.93; - -0.11 -0.38 -1.19 0.43 1.21 2.78 -0.06 0.40] +W1 = [0.54, -1.97, 0.09, -2.14, 1.01, -0.58, 0.45, 0.26; + -0.81, -0.74, 0.63, -1.60, -0.56, -1.05, 1.23, 0.93; + -0.11, -0.38, -1.19, 0.43, 1.21, 2.78, -0.06, 0.40] # Weights associated with the output layer -W2 = [-0.91 0.11 0.52] +W2 = [-0.91, 0.11, 0.52] # Bias associated with the hidden layer -B1 = [-2.698 0.012 2.926] +B1 = [-2.698, 0.012, 2.926] # Bias associated with the output layer B2 = -0.46 # Variable bounds (Used to scale variables after optimization) -xLBD = [0.623, 0.093, 0.259, 6.56, 1114, 0.013, 0.127, 0.004] -xUBD = [5.89, 0.5, 1.0, 90, 25000, 0.149, 0.889, 0.049]; +xLBD = [0.623, 0.093, 0.259, 6.56, 1114.0, 0.013, 0.127, 0.004] +xUBD = [5.89, 0.5, 1.0, 90.0, 25000.0, 0.149, 0.889, 0.049]; ``` ## Construct the JuMP Model and Optimize -We now formulate the problem using standard JuMP [[3](#references)] syntax and optimize it. Note that -we are forming an NLexpression object to handle the summation term to keep the code -visually simple, but this could be placed directly in the JuMP `@NLobjective` expression -instead. +We now formulate the problem using standard JuMP [[3](#References)] syntax and optimize it. Note that we are forming an NLexpression object to handle the summation term to keep the code visually simple, but this could be placed directly in the JuMP [`@NLobjective`](https://jump.dev/JuMP.jl/stable/api/JuMP/#@NLobjective) expression instead. ```julia # Model construction model = Model(optimizer_with_attributes(EAGO.Optimizer, "absolute_tolerance" => 0.001)) @variable(model, -1.0 <= x[i=1:8] <= 1.0) @NLexpression(model, y[r=1:3], sum(W1[r,i]*x[i] for i in 1:8)) -@NLobjective(model, Max, B2 + sum(W2[r]*(2/(1+exp(-2*y[r]+B1[r]))) for r=1:3)) +@NLobjective(model, Max, B2 + sum(W2[r]*(2.0/(1 + exp(-2.0*y[r] + B1[r]))) for r=1:3)) # Solve the model optimize!(model) @@ -62,9 +55,7 @@ optimize!(model) ## Retrieve Results -We then recover the objective value, the solution value, and termination status codes -using standard JuMP syntax. The optimal value and solution values are then rescaled -using the variable bounds to obtain their physical interpretations. +We then recover the objective value, the solution values, and termination status codes using standard JuMP syntax. The optimal value and solution values are then rescaled using the variable bounds to obtain their physical interpretations. ```julia # Access calculated values @@ -73,16 +64,16 @@ xsol = JuMP.value.(x) status_term = JuMP.termination_status(model) status_prim = JuMP.primal_status(model) println("EAGO terminated with a status of $status_term and a result code of $status_prim.") -println("The optimal value is: $(round(fval,digits=5)).") -println("The solution found is $(round.(xsol,digits=3)).") +println("The optimal value is: $(round(fval, digits=5)).") +println("The solution found is $(round.(xsol, digits=3)).") println("") # Rescale values back to physical space -rescaled_fval = ((fval+1)/2)*0.07 -rescaled_xsol = ((xsol.+1.0)./2).*(xUBD-xLBD).+xLBD +rescaled_fval = ((fval + 1.0)/2.0)*0.07 +rescaled_xsol = ((xsol .+ 1.0)./2.0).*(xUBD - xLBD) .+ xLBD println("Rescaled optimal value and solution values:") -println("The rescaled optimal value is: $(round(rescaled_fval,digits=4))") -println("The rescaled solution is $(round.(rescaled_xsol,digits=3)).") +println("The rescaled optimal value is: $(round(rescaled_fval, digits=4))") +println("The rescaled solution is $(round.(rescaled_xsol, digits=3)).") ``` ## References diff --git a/docs/src/quick_start/guidelines.md b/docs/src/quick_start/guidelines.md index 91ae92f0..a4c01959 100644 --- a/docs/src/quick_start/guidelines.md +++ b/docs/src/quick_start/guidelines.md @@ -1,15 +1,10 @@ # Customization Guidelines -This section contains general guidelines on how the functionality of EAGO can be extended -for specific use cases. Many functions in EAGO are extensible, so examples are not provided -for every possible case, but some important functions are covered. If there is a use case -you do not see provided here, but would like to see, please contact -[Robert Gottlieb](https://psor.uconn.edu/person/robert-gottlieb/). +This section contains general guidelines on how the functionality of EAGO can be extended for specific use cases. Many functions in EAGO are extensible, so examples are not provided for every possible case, but some important functions are covered. If there is a use case you do not see provided here, but would like to see, please contact [Robert Gottlieb](https://psor.uconn.edu/person/robert-gottlieb/). ## 1) Creating an Extension -Extensibility in EAGO is based on the `EAGO.ExtensionType` type. To create customized -functions, the recommended method is to create a new structure, as follows: +Extensibility in EAGO is based on the [`ExtensionType`](@ref). To create customized functions, the recommended method is to create a new structure, as follows: ```julia using EAGO @@ -17,9 +12,7 @@ using EAGO struct MyNewStruct <: EAGO.ExtensionType end ``` -To let EAGO know that you would like to use this extension (and any functions you -overload), when you create the JuMP model, declare your new type in the SubSolvers -field of EAGO's optimizer as follows: +To let EAGO know that you would like to use this extension (and any functions you overload), when you create the JuMP model, declare your new type in the `subsolver_block` field of the [`Optimizer`](@ref) as follows: ```julia using JuMP @@ -28,22 +21,11 @@ factory = () -> EAGO.Optimizer(SubSolvers(; t = MyNewStruct() )) model = Model(factory) ``` -The key point to note here is that the new structure is set to `SubSolvers.t`, which -is the field that holds any user-defined extension type. Now, when EAGO calls any of -its functions, it will check to see if a custom function for this new extension has -been created. If so, it will use the new one; if not, it will use the default version -of that function. +The key point to note here is that the new structure is set to [`SubSolvers.t`](@ref EAGO.SubSolvers), which is the field that holds any user-defined extension type. Now, when EAGO calls any of its functions, it will check to see if a custom function for this new extension has been created. If so, it will use the new one; if not, it will use the default version of that function. ## 2) Preprocessing -In EAGO's branch-and-bound routine, preprocessing is performed prior to solving the -lower and upper problems. By default, linear and quadratic contractor methods are -performed, followed by interval constraint propagation, then optimization-based -bounds tightening. An important outcome of EAGO's default preprocessing is that -the `_preprocess_feasibility` field of the `EAGO.GlobalOptimizer` is set to `true`, -unless the subproblem at the current node has been proven infeasible. Therefore, -to bypass preprocessing for your own problem, you must, at a minimum, set this -field to `true`. For example: +In EAGO's branch-and-bound routine, preprocessing is performed prior to solving the lower and upper problems. By default, linear and quadratic contractor methods are performed, followed by interval constraint propagation, then optimization-based bounds tightening. An important outcome of EAGO's default preprocessing is that the `_preprocess_feasibility` field of the [`GlobalOptimizer`](@ref) is set to `true`, unless the subproblem at the current node has been proven infeasible. Therefore, to bypass preprocessing for your own problem, you must, at a minimum, set this field to `true`. For example: ```julia import EAGO: preprocess! @@ -52,20 +34,11 @@ function EAGO.preprocess!(t::MyNewStruct, x::EAGO.GlobalOptimizer) end ``` -The user-defined preprocessing step can be as simple or complex as desired, but -if `_preprocess_feasibility` is not set to `true`, EAGO will assume each node -is infeasible. +The user-defined preprocessing step can be as simple or complex as desired, but if `_preprocess_feasibility` is not set to `true`, EAGO will assume each node is infeasible. ## 3) Lower Problem -By default, EAGO applies Kelley's cutting-plane algorithm [[1](#references)] to solve the lower bounding -problem. This can be overloaded using the same syntax as for the other functions. -Necessary changes to the `EAGO.GlobalOptimizer` that occur within the lower problem -are changing the `_lower_objective_value` and `_lower_feasibility` fields. If the -`_lower_objective_value` field is not changed, branch-and-bound will not update -the lower bound. If `_lower_feasibility` is not set to `true`, the node will be -discarded as infeasible. A minimum functional (though not useful) lower problem -extension is as follows: +By default, EAGO applies Kelley's cutting-plane algorithm [[1](#References)] to solve the lower-problem. This can be overloaded using the same syntax as for the other functions. Necessary changes to the [`GlobalOptimizer`](@ref) that occur within the lower problem are changing the `_lower_objective_value` and `_lower_feasibility` fields. If the `_lower_objective_value` field is not changed, branch-and-bound will not update the lower bound. If `_lower_feasibility` is not set to `true`, the node will be discarded as infeasible. A minimum functional (though not useful) lower problem extension is as follows: ```julia import EAGO: lower_problem! @@ -75,32 +48,13 @@ function EAGO.lower_problem!(t::MyNewStruct, x::EAGO.GlobalOptimizer) end ``` -Any arbitrarily complex lower problem can be substituted here in place of EAGO's -default method, as long as these fields are updated. Note also that, although there -is a separate upper problem function, if the lower problem is being replaced by -an algorithm that also calculates an upper objective value, the necessary fields -to update in `upper_problem!` can simply be updated here, and the `upper_problem!` -can be overloaded by a function that does `nothing`. +Any arbitrarily complex lower problem can be substituted here in place of EAGO's default method, as long as these fields are updated. Note also that, although there is a separate upper problem function, if the lower problem is being replaced by an algorithm that also calculates an upper objective value, the necessary fields to update in [`upper_problem!`](@ref EAGO.upper_problem!) can simply be updated here, and the [`upper_problem!`](@ref EAGO.upper_problem!) can be overloaded by a function that does `nothing`. ## 4) Upper Problem -By default, the upper bounding problem is run on every node up to depth -`upper_bounding_depth`, and is triggered with a probability of `0.5^(depth - upper_bounding_depth)` -afterwards for continuous problems. For integer problems, this approach -is used in addition to running on every node up to depth `upper_bounding_depth + cont_depth`, -with another trigger of probability `0.5^(depth - upper_bounding_depth - cont_depth)`. -The `upper_bounding_depth` and `cont_depth` are fields of `GlobalOptimizer._parameters` -and can be changed from their default values when the JuMP model is created, or -at any time afterwards. If any of these trigger conditions are met, the -default EAGO upper problem runs a local NLP solve. - -The important fields to update in the `upper_problem!` are the `_upper_objective_value` -and `_upper_feasibility` fields. If `_upper_objective_value` is not updated, -the upper bound in the branch-and-bound algorithm will not update and the problem -will not converge. If `_upper_feasibility` is not set to true, then any changes -made to `_upper_objective_value` will not be updated for each node and the problem -will not converge. A minimum functional (though not useful) upper problem -extension is as follows: +By default, the upper-bounding problem is run on every node up to depth `upper_bounding_depth`, and is triggered with a probability of `0.5^(depth - upper_bounding_depth)` afterwards for continuous problems. For integer problems, this approach is used in addition to running on every node up to depth `upper_bounding_depth + cont_depth`, with another trigger of probability `0.5^(depth - upper_bounding_depth - cont_depth)`. The `upper_bounding_depth` and `cont_depth` are fields of [`EAGOParameters`](@ref) and can be changed from their default values when the JuMP model is created, or at any time afterwards. If any of these trigger conditions are met, the default EAGO upper problem runs a local NLP solve. + +The important fields to update in the [`upper_problem!`](@ref EAGO.upper_problem!) are the `_upper_objective_value` and `_upper_feasibility` fields. If `_upper_objective_value` is not updated, the upper bound in the branch-and-bound algorithm will not update and the problem will not converge. If `_upper_feasibility` is not set to true, then any changes made to `_upper_objective_value` will not be updated for each node and the problem will not converge. A minimum functional (though not useful) upper problem extension is as follows: ```julia import EAGO: upper_problem! @@ -110,27 +64,13 @@ function upper_problem!(t::MyNewStruct, x::EAGO.GlobalOptimizer) end ``` -This example upper problem will set the upper bound on the objective value to -`Inf` for each node. Given that no useful information is provided here, we could -also have set `x_upper_feasibility` to `false` (or equivalently, remove the line -where we set it to `true`), and the global upper bound would never be updated. +This example upper problem will set the upper bound on the objective value to `Inf` for each node. Given that no useful information is provided here, we could also have set `x_upper_feasibility` to `false` (or equivalently, remove the line where we set it to `true`), and the global upper bound would never be updated. -Note that if the `_upper_objective_value` is changed elsewhere, such as in the -definition for the `lower_problem!`, the `_upper_feasibility` flag must be set -to `true`. If this is not done, the change to the `_upper_objective_value` will -be discarded. +Note that if the `_upper_objective_value` is changed elsewhere, such as in the definition for the [`lower_problem!`](@ref EAGO.lower_problem!), the `_upper_feasibility` flag must be set to `true`. If this is not done, the change to the `_upper_objective_value` will be discarded. ## 5) Convergence Check -By default, EAGO checks to see if the lower and upper bounds have converged to -within either the absolute or relative tolerance. This method of checking convergence -may not be desired if, for example, only the absolute tolerance is relevant, and you -want to ensure that the program does not end prematurely due to a relative tolerance -limit being reached. The fields to check are `_lower_objective_value` and -`_upper_objective_value` for the best-identified global lower and upper bounds, -respectively. This function should return `true` if the lower and upper bounds have -converged, and `false` otherwise. An example of how to specify that the convergence -check only use the absolute tolerance is as follows: +By default, EAGO checks to see if the lower and upper bounds have converged to within either the absolute or relative tolerance. This method of checking convergence may not be desired if, for example, only the absolute tolerance is relevant, and you want to ensure that the program does not end prematurely due to a relative tolerance limit being reached. The fields to check are `_lower_objective_value` and `_upper_objective_value` for the best-identified global lower and upper bounds, respectively. This function should return `true` if the lower and upper bounds have converged, and `false` otherwise. An example of how to specify that the convergence check only use the absolute tolerance is as follows: ```julia import EAGO: convergence_check @@ -142,12 +82,7 @@ end ## 6) Postprocessing -Postprocessing is the final step before a node is branched on. By default, EAGO -performs duality-based bounds tightening[2] up to an iteration limit set by -`dbbt_depth` in the `GlobalOptimizer._parameters` field. The important field -to update in postprocessing is `_postprocess_feasibility`, which must be set -to `true` for EAGO to branch on any given node. The minimum working postprocessing -function is therefore: +Postprocessing is the final step before a node is branched on. By default, EAGO performs duality-based bounds tightening [[2](#References)] up to an iteration limit set by `dbbt_depth` in the [`EAGOParameters`](@ref) field. The important field to update in postprocessing is `_postprocess_feasibility`, which must be set to `true` for EAGO to branch on any given node. The minimum working postprocessing function is therefore: ```julia import EAGO: postprocess! @@ -160,22 +95,9 @@ If `_postprocess_feasibility` is not set to `true`, no nodes will be branched on ## 7) Termination Check -This is the check that occurs on each iteration of the branch-and-bound algorithm -that determines whether the algorithm continues or not. By default, several -conditions are checked for such as the satisfaction of absolute or relative -tolerances, solution infeasibility, or other specified limits. This function -returns `true` if any of the stopping conditions have been met, and -branch-and-bound should stop, and `false` otherwise. The important fields to -update are `_end_state`, which takes values of `EAGO.GlobalEndState`, -`_termination_status_code`, which takes values of `MathOptInterface.TerminationStatusCode`, -and `_result_status_code`, which takes values of `MathOptInterface.ResultStatusCode`. -Combined, these fields provide information about the branch-and-bound completion -status and result feasibility. - -As an example, suppose we have updated the `convergence_check` function to -only check for absolute tolerance, and based on our knowledge of the problem, -this is the only condition we care about, and we know the solution will be -optimal. We could then overload the `termination_check` function as follows: +This is the check that occurs on each iteration of the branch-and-bound algorithm that determines whether the algorithm continues or not. By default, several conditions are checked for such as the satisfaction of absolute or relative tolerances, solution infeasibility, or other specified limits. This function returns `true` if any of the stopping conditions have been met, and branch-and-bound should stop, and `false` otherwise. The important fields to update are `_end_state`, which takes values of `EAGO.GlobalEndState`, `_termination_status_code`, which takes values of [`MOI.TerminationStatusCode`](https://jump.dev/MathOptInterface.jl/stable/reference/models/#MathOptInterface.TerminationStatusCode), and `_result_status_code`, which takes values of [`MOI.ResultStatusCode`](https://jump.dev/MathOptInterface.jl/stable/reference/models/#MathOptInterface.ResultStatusCode). Combined, these fields provide information about the branch-and-bound completion status and result feasibility. + +As an example, suppose we have updated the [`convergence_check`](@ref EAGO.convergence_check) function to only check for absolute tolerance, and based on our knowledge of the problem, this is the only condition we care about, and we know the solution will be optimal. We could then overload the [`termination_check`](@ref EAGO.termination_check) function as follows: ```julia import EAGO: termination_check diff --git a/docs/src/quick_start/interval_bb.md b/docs/src/quick_start/interval_bb.md new file mode 100644 index 00000000..5ad6e60e --- /dev/null +++ b/docs/src/quick_start/interval_bb.md @@ -0,0 +1,140 @@ +# Standard-Use Example 2 + +This example is also provided [here as a Jupyter Notebook](https://github.com/PSORLab/EAGO-notebooks/blob/master/notebooks/nlpopt_interval_bnb.ipynb). + +### Using EAGO's Basic Optimizer With User-Defined Subroutines + +In this section, we construct an optimizer that uses EAGO's basic NLP solution routine with user-defined lower and upper-bounding problems. The [`Optimizer`](@ref) structure supplies a number of parameters and stored structures that advanced users may find useful for constructing specialized solution routines. + +In this example, we'll forgo extensive integration into the [`Optimizer`](@ref) and simply replace the lower and upper-bounding problems to construct a B&B routine that solves the following problem to global optimality using bounds obtained from interval arithmetic: + +```math +\begin{aligned} +& \min_{\mathbf x \in X} \;\; \sin(x_{1}) x_{2}^{2} - \cos(x_{3}) / x_{4}\\ +& X = [-10, 10] \times [-1, 1] \times [-10, 10] \times [2, 20]. +\end{aligned} +``` + +We begin by importing EAGO, IntervalArithmetic [[1](#References)], and JuMP [[2](#References)]. + +```julia +using EAGO, IntervalArithmetic, JuMP +``` + +We now define the `IntervalExt` struct as a subtype of the [`ExtensionType`](@ref). + +```julia +struct IntervalExt <: EAGO.ExtensionType end +``` + +## Define a Custom Lower-Bounding Problem + +A valid lower bound is obtained from the lower bound of the natural interval extension using the [IntervalArithmetic.jl](https://github.com/JuliaIntervals/IntervalArithmetic.jl) [[1](#References)] package. The `LowerProblem` is dispatched using the new `IntervalExt` structure and the [`GlobalOptimizer`](@ref) structure, computes the bound using interval arithmetic, and stores the results to the appropriate field of the [`GlobalOptimizer`](@ref). Note that the problem is unconstrained on the domain so we can assume it is always feasible. Further, since the interval bound is constrained along the entire domain associated with a node, no additional cuts will be beneficial and thus we've disabled them using the `_cut_add_flag` field. + +```julia +import EAGO: lower_problem! +function lower_problem!(t::IntervalExt, x::EAGO.GlobalOptimizer) + # Retrieve bounds at current node + n = x._current_node + lower = n.lower_variable_bounds + upper = n.upper_variable_bounds + + # Define X for the node and compute the interval extension + x_value = Interval.(lower, upper) + F = sin(x_value[1])*x_value[2]^2 - cos(x_value[3])/x_value[4] + x._lower_objective_value = F.lo + x._lower_solution = IntervalArithmetic.mid.(x_value) + x._lower_feasibility = true + x._cut_add_flag = false + + return +end +``` + +## Define a Custom Upper-Bounding Problem + +Since the problem is unconstrained, any feasible point represents a valid upper bound. Thus, if we arbitrarily evaluate the function at the midpoint, we obtain a valid upper bound. This function constructs an upper bound in this manner then stores the results to the appropriate field of the [`GlobalOptimizer`](@ref). + +```julia +import EAGO.upper_problem! +function EAGO.upper_problem!(t::IntervalExt, x::EAGO.GlobalOptimizer) + # Retrieve bounds at current node + n = x._current_node + lower = n.lower_variable_bounds + upper = n.upper_variable_bounds + + # Compute midpoint value and evaluate at that point + x_value = 0.5*(upper + lower) + f_val = sin(x_value[1])*x_value[2]^2-cos(x_value[3])/x_value[4] + x._upper_objective_value = f_val + x._upper_solution = x_value + x._upper_feasibility = true + + return +end +``` + +## Disable Unnecessary Routines + +It is entirely possible to disable domain reduction by manipulating keyword arguments supplied to the optimizer. However, for simplicity's sake we'll simply overload the default preprocessing and postprocessing methods and indicate that there are no conditions under which EAGO should cut the node. + +```julia +import EAGO: preprocess!, postprocess!, cut_condition +function EAGO.preprocess!(t::IntervalExt, x::EAGO.GlobalOptimizer) + x._preprocess_feasibility = true + return +end +function EAGO.postprocess!(t::IntervalExt, x::EAGO.GlobalOptimizer) + x._postprocess_feasibility = true + return +end +EAGO.cut_condition(t::IntervalExt, x::EAGO.GlobalOptimizer) = false +``` + +## Construct the JuMP Model and Optimize + +We now add our optimizer to a JuMP [[2](#References)] model, provide variable bounds, and optimize. + +```julia +# Create a factory that specifies the interval extension in EAGO's SubSolver +factory = () -> EAGO.Optimizer(SubSolvers(; t = IntervalExt())) + +# Create a JuMP model using the factory, and with the absolute tolerance set by keyword argument +m = Model(optimizer_with_attributes(factory, + "absolute_tolerance" => 0.001 + )) + +# Add variables, bounds, and the objective function +x_L = [-10.0, -1.0, -10.0, 2.0] +x_U = [10.0, 1.0, 10.0, 20.0] +@variable(m, x_L[i] <= x[i=1:4] <= x_U[i]) +@NLobjective(m, Min, sin(x[1])*x[2]^2 - cos(x[3])/x[4]) + +# Perform the optimization +optimize!(m) +``` + +## Retrieve Results + +The objective value, solution, termination status, and primal status can then be accessed via the standard JuMP interface. + +```julia +fval = JuMP.objective_value(m) +xsol = JuMP.value.(x) +status_term = JuMP.termination_status(m) +status_prim = JuMP.primal_status(m) + +println("EAGO terminated with a status of $status_term and a result code of $status_prim") +println("The optimal value is: $(round(fval, digits=3)), the solution found is $(round.(xsol, digits=4)).") +``` + +## Advice for More Advanced Constructions + +The default [`lower_problem!`](@ref EAGO.lower_problem!) and [`upper_problem!`](@ref EAGO.upper_problem!) should be used as templates for error handling and retrieving information from MOI models. + +Essentially all of EAGO's subroutines stored to a field in the [`Optimizer`](@ref) structure can be reset as user-defined functions. + +## References + +1. IntervalArithmetic.jl \[Computer software\] (2019). Retrieved from https://github.com/JuliaIntervals/IntervalArithmetic.jl +2. Iain Dunning and Joey Huchette and Miles Lubin. JuMP: A Modeling Language for Mathematical Optimization, SIAM Review, SIAM 59 (2017), pp. 295-320. diff --git a/docs/src/quick_start/qc_Equation_1.png b/docs/src/quick_start/qc_Equation_1.png deleted file mode 100644 index 48aef029a6fa6f79155abee0f5b85e5403e6476d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13854 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 diff --git a/docs/src/quick_start/qc_Equation_2.png b/docs/src/quick_start/qc_Equation_2.png deleted file mode 100644 index ddad2085576d4afd63d06436b968016ccdc9efa5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3968 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 JC6AuH`yUbisYU<* diff --git a/docs/src/quick_start/qc_Equation_3.png b/docs/src/quick_start/qc_Equation_3.png deleted file mode 100644 index 3bdb7d91ea0f6e6767266df6361cb9205ca97b45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6300 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 diff --git a/docs/src/quick_start/qs_landing.md b/docs/src/quick_start/qs_landing.md index 20512079..0c0c2d2f 100644 --- a/docs/src/quick_start/qs_landing.md +++ b/docs/src/quick_start/qs_landing.md @@ -1,24 +1,15 @@ # Quick Start -EAGO is a global optimizer primarily meant to be used with the JuMP algebraic modeling -language. Typical use will involve installing EAGO and JuMP, creating a problem using -JuMP syntax, and passing the problem to the EAGO optimizer. +EAGO is a global optimizer primarily meant to be used with the JuMP algebraic modeling language. Typical use will involve installing EAGO and JuMP, creating a problem using JuMP syntax, and passing the problem to the [`Optimizer`](@ref). ## Customization -EAGO is designed to be easily extensible. Some of the examples that follow include use -cases where the standard EAGO functionality is overloaded and readily incorporated into -the main optimization routine. Information on how to extend the main branch-and-bound -functions (including lower and upper bounding routines) can be found in the -[Customization Guidelines](https://psorlab.github.io/EAGO.jl/dev/quick_start/guidelines/) section. +EAGO is designed to be easily extensible. Some of the examples that follow include use cases where the standard EAGO functionality is overloaded and readily incorporated into the main optimization routine. Information on how to extend the main branch-and-bound functions (including lower and upper-bounding routines) can be found in the [Customization Guidelines](@ref) section. ## Examples -The following pages in this section include several representative examples of how EAGO -can be used. Additional (and in some cases, shortened) examples can be found in the -[EAGO-notebooks repository](https://github.com/PSORLab/EAGO-notebooks/blob/master/notebooks). -Examples and instructional pages in this section include: +The following pages in this section include several representative examples of how EAGO can be used. Additional (and in some cases, shortened) examples can be found in the [EAGO-notebooks repository](https://github.com/PSORLab/EAGO-notebooks/blob/master/notebooks). Examples and instructional pages in this section include: - [Standard-Use Example 1](@ref): A base-case optimization problem solved using the EAGO optimizer. No extensions or function overloading required. -- [Standard-Use Example 2](@ref): user-defined functions (TODO) -- [Advanced-Use Example 1](@ref): A quasiconvex optimization problem solved by overloading some of EAGO's functionality to implement a bisection-based algorithm instead of typical branch-and-bound. (TODO, but see the [Jupyter Notebook version](https://github.com/PSORLab/EAGO-notebooks/blob/master/notebooks/custom_quasiconvex.ipynb)) +- [Standard-Use Example 2](@ref): An interval bounding example where the user redefines EAGO's lower and upper-bounding functions. +- [Advanced-Use Example 1](@ref): A quasiconvex optimization problem solved by overloading some of EAGO's functionality to implement a bisection-based algorithm instead of typical branch-and-bound. - [Advanced-Use Example 2](@ref): Overloading the branch-and-bound algorithm with a custom extension type. diff --git a/docs/src/quick_start/quasiconvex.md b/docs/src/quick_start/quasiconvex.md index 49080c2e..c6aee502 100644 --- a/docs/src/quick_start/quasiconvex.md +++ b/docs/src/quick_start/quasiconvex.md @@ -1,101 +1,151 @@ # Advanced-Use Example 1 -This example still needs to be updated. This example is also provided [here as a Jupyter Notebook](https://github.com/PSORLab/EAGO-notebooks/blob/master/notebooks/custom_quasiconvex.ipynb). ### Customizing EAGO to Solve a Quasiconvex Problem -In this example, we'll adapt EAGO to implement the bisection-based algorithm used to solve -a quasiconvex optimization problem presented in [[1](#references)]: +In this example, we'll adapt EAGO to implement the bisection-based algorithm used to solve a quasiconvex optimization problem presented in [[1](#References)]: + +```math +\begin{aligned} +f^{*} = & \min_{\mathbf y \in Y} f(\mathbf y)\\ +{\rm s.t.} \;\; & \sum_{i = 1}^{5} i \cdot y_{i} - 5 = 0\\ +& \sum_{i = 1}^{5} y_{i}^{2} - 0.5\pi \leq 0\\ +& -\bigg(\frac{1}{2} y_{1}^{2} + \frac{1}{2} y_{2}^{2} + 2 y_{1} y_{2} + 4 y_{1} y_{3} + 2 y_{2} y_{3} \bigg) \leq 0\\ +& -y_{1}^{2} - 6 y_{1} y_{2} - 2 y_{2}^{2} + \cos (y_{1}) + \pi \leq 0\\ +& Y = [0,5]^{5} +\end{aligned} +``` -![Equation 1](qc_Equation_1.png) +where -where: +```math +\begin{aligned} +f(\mathbf y) = -\frac{\ln ((5 + y_{1})^{2} + \sum_{i = 1}^{5} y_{i})}{1 + \sum_{i = 1}^{5} y_{i}^{2}}. +\end{aligned} +``` -![Equation 2](qc_Equation_2.png) +Interval analysis shows that the objective value is bounded by the interval ``F`` such that ``f^{*} \in F = [f^{L}, f^{U}] = [-5, 0]``. Introducing an auxiliary variable ``t \in T = F`` allows the problem to be formulated as: -Interval analysis shows that the objective value is bounded by the interval **F** such that -$f^*∈ F = [f^L, f^U] = [-5, 0]$. Introducing an auxiliary variable $t∈ T = F$ allows the -problem to be formulated as: +```math +\begin{aligned} +t^{*} = & \min_{\mathbf y \in Y, t \in T} t\\ +{\rm s.t.} \;\; & (24) - (27)\\ +& f(\mathbf y) - t \leq 0\\ +& Y = [0,5]^{2}, \;\; T = [-5,0]. +\end{aligned} +``` -![Equation 3](qc_Equation_3.png) +Let ``\phi_{\tau}(\mathbf y) = f(\mathbf y) - \tau`` such that ``\tau = (t^{L} + t^{U})/2``. We solve for ``\mathbf y`` subject to constraints ``(24) - (27)`` where ``\phi_{\tau} (\mathbf y) \leq 0``. If this is feasible, ``t^{*} \in [t^{L},\tau]``, else ``t^{*} \in [τ, t^{U}]``. The interval containing ``t^{*}`` is kept and the other is fathomed. This manner of bisection is repeated until an interval containing a feasible solution with a width of at most ``\epsilon`` is located [[2](#References)]. -Let $ϕ_τ(y) = f(y) - τ$ such that $\tau = (t^L + t^U)/2$. We solve for $y$ subject to -constraints (24)-(27) where $ϕ_τ (y) ≤ 0$. If this is feasible, $t^*∈ [t^L,τ]$, else -$t^*∈ [τ, t^U]$. The interval containing $t^*$ is kept and the other is fathomed. This -manner of bisection is repeated until an interval containing a feasible solution with a -width of at most ϵ is located [[2](#references)]. +## Customizing EAGO's Script -## EAGO Implementation +First, the preprocessing step, upper problem, and postprocessing routines are short-circuited as only a single optimization problem needs to be solved at each iteration. -In the first block, we input parameters values supplied in the paper for $W_1$, $W_2$, -$B_1$, and $B_2$ into Julia as simple array objects. We also input bounds for the variables -which are used to scale the values obtained from optimization from [-1, 1] back into the -design values. +```julia +using MathOptInterface, EAGO, JuMP +import EAGO: Optimizer, GlobalOptimizer + +struct QuasiConvex <: EAGO.ExtensionType end +import EAGO: preprocess!, upper_problem!, postprocess! +function EAGO.preprocess!(t::QuasiConvex, x::GlobalOptimizer) + x._preprocess_feasibility = true +end +function EAGO.upper_problem!(t::QuasiConvex, x::GlobalOptimizer) + x._upper_feasibility = true +end +function EAGO.postprocess!(t::QuasiConvex, x::GlobalOptimizer) + x._postprocess_feasibility = true +end +``` + +Next, we specify that only an absolute tolerance should be checked for convergence and termination. ```julia -using JuMP, EAGO +import EAGO: convergence_check, termination_check +function EAGO.convergence_check(t::QuasiConvex, x::GlobalOptimizer) + gap = (x._upper_objective_value - x._lower_objective_value) + return (gap <= x._parameters.absolute_tolerance) +end +function EAGO.termination_check(t::QuasiConvex, x::GlobalOptimizer) + flag = EAGO.convergence_check(t, x) + if flag + x._end_state = EAGO.GS_OPTIMAL + x._termination_status_code = MathOptInterface.OPTIMAL + x._result_status_code = MathOptInterface.FEASIBLE_POINT + end + return flag +end +``` -# Weights associated with the hidden layer -W1 = [ 0.54 -1.97 0.09 -2.14 1.01 -0.58 0.45 0.26; - -0.81 -0.74 0.63 -1.60 -0.56 -1.05 1.23 0.93; - -0.11 -0.38 -1.19 0.43 1.21 2.78 -0.06 0.40] +We then indicate that only the sixth variable, representing ``t``, should be branched on. Since we will apply our knowledge about which ``t^{*}`` should be kept in the lower problem definition, we also short-circuit the [`EAGO.repeat_check`](@ref) function here to tell EAGO not to branch this node, but instead to repeatedly evaluate it. -# Weights associated with the output layer -W2 = [-0.91 0.11 0.52] +```julia +import EAGO: repeat_check +branch_variable = [i == 6 for i=1:6] +EAGO.repeat_check(t::QuasiConvex, x::GlobalOptimizer) = true +``` + +In the lower problem, we then specify that the problem is to be solved locally for a fixed ``t`` value. The objective value is then updated and the problem is contracted in order to discard the region which is known to not contain the optimal value. -# Bias associated with the hidden layer -B1 = [-2.698 0.012 2.926] +```julia +import EAGO: lower_problem! +function EAGO.lower_problem!(t::QuasiConvex, x::GlobalOptimizer) + y = x._current_node + indx = x._sol_to_branch_map[6] + lower = y.lower_variable_bounds[indx] + upper = y.upper_variable_bounds[indx] + midy = (lower + upper)/2.0 + y.lower_variable_bounds[indx] = midy + y.upper_variable_bounds[indx] = midy + EAGO.solve_local_nlp!(x) + feas = x._upper_feasibility + y.lower_variable_bounds[indx] = feas ? lower : midy + y.upper_variable_bounds[indx] = feas ? midy : upper + x._lower_objective_value = y.lower_variable_bounds[indx] + x._upper_objective_value = y.upper_variable_bounds[indx] + x._lower_feasibility = true + return +end +``` -# Bias associated with the output layer -B2 = -0.46 +We now define the optimizer factory to extend the core EAGO optimizer for this special problem. The [`SubSolvers`](@ref) constructor is used to set the extension type (`t`), as well as the relaxed optimizer (`r`) and upper-bounding optimizer (`u`), if necessary. In this case, we will use the default solvers and only set the extension type. -# Variable bounds (Used to scale variables after optimization) -xLBD = [0.623, 0.093, 0.259, 6.56, 1114, 0.013, 0.127, 0.004] -xUBD = [5.89, 0.5, 1.0, 90, 25000, 0.149, 0.889, 0.049]; +```julia +factory = () -> Optimizer(SubSolvers(; t = QuasiConvex())) ``` ## Construct the JuMP Model and Optimize -We now formulate the problem using standard JuMP [[3](#references)] syntax and optimize it. Note that -we are forming an NLexpression object to handle the summation term to keep the code -visually simple, but this could be placed directly in the JuMP `@NLobjective` expression -instead. +We now build the JuMP [[3](#References)] model representing this problem, solve it, and retrieve the solution. ```julia -# Model construction -model = Model(optimizer_with_attributes(EAGO.Optimizer, "absolute_tolerance" => 0.001)) -@variable(model, -1.0 <= x[i=1:8] <= 1.0) -@NLexpression(model, y[r=1:3], sum(W1[r,i]*x[i] for i in 1:8)) -@NLobjective(model, Max, B2 + sum(W2[r]*(2/(1+exp(-2*y[r]+B1[r]))) for r=1:3)) - -# Solve the model -optimize!(model) +opt = optimizer_with_attributes(factory, + "absolute_tolerance" => 1E-8, + "branch_variable" => branch_variable, + "iteration_limit" => 1000) +m = Model(opt) +@variable(m, ((i<6) ? 0.0 : -5.0) <= y[i=1:6] <= ((i<6) ? 5.0 : 0.0)) +@constraint(m, sum(i*y[i] for i=1:5) - 5.0 == 0.0) +@constraint(m, sum(y[i]^2 for i=1:5) - 0.5*pi^2 <= 0.0) +@expression(m, expr1, 2.0*y[1]*y[2] + 4.0*y[1]*y[3] + 2.0*y[2]*y[3]) +@constraint(m, -(0.5*y[1]^2 + 0.5*y[2]^2 + y[3]^2 + expr1) <= 0.0) +@NLexpression(m, expr2, log((5.0 + y[1])^2 + sum(y[i] for i=1:5))) +@NLconstraint(m, -y[1]^2 - 6.0*y[1]*y[2] - 2.0*y[2]^2 + cos(y[1]) + pi <= 0.0) +@NLconstraint(m, -expr2/(1.0 + sum(y[i]^2 for i=1:5)) - y[6] <= 0.0) +@objective(m, Min, y[6]) + +JuMP.optimize!(m) ``` ## Retrieve Results -We then recover the objective value, the solution value, and termination status codes -using standard JuMP syntax. The optimal value and solution values are then rescaled -using the variable bounds to obtain their physical interpretations. +We then recover the solution values and the objective value using standard JuMP syntax. ```julia -# Access calculated values -fval = JuMP.objective_value(model) -xsol = JuMP.value.(x) -status_term = JuMP.termination_status(model) -status_prim = JuMP.primal_status(model) -println("EAGO terminated with a status of $status_term and a result code of $status_prim.") -println("The optimal value is: $(round(fval,digits=5)).") -println("The solution found is $(round.(xsol,digits=3)).") -println("") - -# Rescale values back to physical space -rescaled_fval = ((fval+1)/2)*0.07 -rescaled_xsol = ((xsol.+1.0)./2).*(xUBD-xLBD).+xLBD -println("Rescaled optimal value and solution values:") -println("The rescaled optimal value is: $(round(rescaled_fval,digits=4))") -println("The rescaled solution is $(round.(rescaled_xsol,digits=3)).") +solution = JuMP.value.(y[1:5]) +global_obj_value = JuMP.value.(y[6]) +print("Global solution at y*=$solution with a value of f*=$global_obj_value") ``` ## References diff --git a/docs/src/semiinfinite/SIPProbFormulation.png b/docs/src/semiinfinite/SIPProbFormulation.png deleted file mode 100644 index 95419e4d3ab77857253483d9fdc19097a634f32d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21285 zcmdpdWmFwK)GqGsdMJfb+^xXD-Cc^iyK``Ncemm$2X`&*?o!;nNI%}Y?(h5K`*~+& zR%VjPPG-+eCeO2z2t|1bR3suK2nYyNDM?Xf2nZM;1O#L?0`zCfSC@Y^pAn?9vV<^1 z%@oPW=M9Xxkem<%M136cn;|R&1eCX;tg6_*fBzmH9?s9tFD@=#Utd2yK8}x%@9*#b z{{1^XJ{}bnb#``kaB$%4?99NxaCv!ob93Y1;Ba+yrJ|xDEiHX}dwX(nVq;^In3(wZ z_?VKCqM@Pj^z<}4J9~P1`u_fYeSK|ZW#!@Fad&rTXJ_~F^3vbm@8;&Fudgp6BErhb zDk&*xWMtIT)Wprr9UL5NZEdZjq{Pn7&d<-UtgIXs7Phyyr>m=LVq$W1bhN&{9vB!{ zU0p3ID%#%OE+;1^At5m}H8nCa^5@SV5D2ukwq|c{FD@?L(9n>dpU=U;k&%(n+1Xi9 zQPI}crmn7DR#x`*_V)AV&(_vfSy@?cZ|~vZVFLq$)YR1FLlCW@e_Rr#Cq{85gw9l(^Fbn8Xq4oB_*}A zw3L*Tl$Mqj85t=cAh5c+Ix#W9#Ka^hC^$AYW?^ArY;4TO#}^tJnx39sSXgLoZtmmb zQ(Rm;Jv}WWBeT7|y}P?RG&JPy?yjJqz{$y}si|30Q`6hq8y+66qoY$&Qu6E9FL`YYHHfu-Oa|vwz#<1*x0zSv2l2K$i>Cg+}vDQ zS=rLkva+(GrKP2+s_NCil=@A)j&^URyEjdo22)4|d7cM>x`+eWS{uNeKCU9^7 zO#&GjSE3sIu%kR|i9fO=u?5YT4BhjEBE6oWieXrOOMx97)E|8uiJe(QoflM&#LS98 z_J^6Hn{}wD*WKqIK5;L$aH3hhQC*xFIhlnhPFLp-;h10TOJBuau%ww;G8=00PZk== zJ#j3;n-0LsL;L8DdG9mPn_Z-%`pbc4g5k1ZUu1>1!1}OTfUI~bn}~bQAsBLvU-df zF?diAKcp0m{#MQKPw#NV1Ioz-#We^G){?p5NHMhzV~WfI;-&S59rtkBKc^LTBxGH7 z2T>B{Mk(2k<@gEaf!fjUTjj}wvyfK(5pux@6u)&F^%xo4q-(TYd>4Q10V#X&9{L)o zWLPP3^6dxDdHq76jG-Mpv=t@0qn+r&Z zCSH>8vI}+mP5K$vQLLnuj0XrmGUfu`$$OslnCS$p$n)i#9BcAv433_}EN~9(1)=FG zU0{yGSyr(YiUQo<^CmdD2qWzVZBUw|YJM>4jPYp8zp!$j*FVZ^@Zrnc=}e#>NYAaP zP;yIGI4#-c;_Eg;1e@XYV16Q$>WTBT-wQyf^-Km5zd?bZl;{2V0iex<1V8u=3d+PQkX|h_RvUu4Yt_9BS{O$!c4eLe8gLbF4=bW;BrMf#lG} zii(BHp%x=TfcZ1@B$<5~-L3UVoNFn{7CRy@Ut60eJcBG_z;PjDrx~czM`Bfnb=CSU z2q^x70@uza^sNSgvhzZ{sBA(1el}K;&0|uPTq!cUV%7^j>=dz?G(@n z;mfK+wYeb|8EU!71EEq+h0x;R_>-?7s(t+{+ppoq+hOSPEZgy9{dht$!MLQ6@b)M5 zH>)(d*qvB!2s<|DF8Jx~i~z9+X^O_+7P0!Is1b#+aVmm7s`sDA)6&4}C*%iBX}n8) zw*Q2_!8{MBbq~9@o>0O;CwmHv8yf^;;)@4Aa`IJKAMs(a3)8u7Hrph)`=4mNY-kur zq^uBykcyg7k2r58;u|PAl2M{nBsKloxGI)#l_;B|#f`xN3fCqimi5g9BW zRFC>0d!O&DOg3l=t8x>$6(Vm5YpO%a`J&YQmDEM48{v|_wqm5mi-gs04^wtFGT&AT zgPfTtJC398Cnl!{Vh-H$K%NxmNknpjaEGjq{uEX$!sV2_(j12wfl%Zvxx>EK>w$t@ zh~fA?gJGv(4o-(UI!j<6`c10o##bngOG%wTv<^!}3}|=@uKq$3-jLE->O9miv@N|- zExP_=C~L9S5P?Q8yV2!$l4UVr}dG*aIbScL)P|ob5@6{a{e($`Ug|OPFH&f?mp*ms!DtISWAz^s zkPq?hmd_rT>jC$!GI%TABH&+!y#9sMdE#?=ek@OG05*;ZRrEQ3O&&N{-j)SpX}8s> z@KQSE2gPnUw9IZl0v1zCn=>hCU_Vu+C8$_J_Hh8$rk6a6Y`!(@R@WiQ+Yd=anhp$1 z8%-Y{d&GEHi2{Y6i}H(yZQ9+-1JD07)~EqLM~CRk=-mnPM)lCak>xr zP4Ny#XgufYMR{VWYKCp!zOKYmz*98ll@2V?8q&xlKM0hBDx_EjoeHV!SE2h9 z|4LsFVOvbG56IenAR;BY0*N-$nu2WXBUS*E#tAHGO;Wv-K_%z&#Uo9Yo0#12JSd4c zL|6oB=!e?*aGoPojw%{$0<%T+f2-b;n>n!TBFf-Hm}1ufdpDyUgp`uMukP@7{Z*zc zJ^0Cs0axgXbYsByt`GRYl0;TaaL4C6n}TLiXF#9oX%kn^X+?(Tm8==xO~dJ5{rik1 ziQ2gnar_rB)^e@EDtBiS*X$)KZeuy_xE_?{yHL$sY;&VN-IKJS&M)vK_gSGb`(juh z=TKxP75C|z-uT+1rnQ*-f~pO=r-aEWz`LncTc{^$9owX1c1$oF`D5jHR`T>CP?>Iw z)Is|dIe^d3WBs>lmVz7Id9j7dG7pJbsS&9oRJ8ree$!7^;o*)Jx13!XMfmrhjJ! zpY!ps%OLhbtZ4sXr?GKgl4=faa@}-=OVfPRrd^#|Y}j)Q(#|*R$McQHwGW8$pKSO= zUH?F|GN)m)$Y&yhbk5d)V>iGBuCsokr?f4qQ2jw$xS{UJJ&O#CL=Y!zD1 zU}GZd-#^UWk{gtVEjR{9^&PI*kF#!%%u4?_L?TFn4Fa#3KA(f`8HKP zqD;7SI$PC3S)1HUZAy?o%1GZtzi#}9%Ol#~u9Q3-wAS09ds7e(&x{FcHFO`Y`K5b^ zufG`5@Ty?w7Y7Bh6uX|}IOG9nW&w%oglQ~~(+p;V)}hA;pxtm_?% zP179PN}U&{dBZMCXeRSUvV&(RrD$MG@of<03)%9Xh~^Rzn;L&!MLldL3H$q5np~V6 zH9bE=UUVIUtKj%Apw=y+V+hf*BJ(dRvntddGPi?KgVxOq znrw=S&>w*O{-z2h?jb-nrg|8x{|7ulHLAjfel#m#oVtk+X&fcn0a1kieOOnpXfG<} zbDS}1Z`YIE`wKN=Oa59!lf%4Z;f?dHmFcE(C~!rS%>wdI7|Ej`bC6BT{QO&_2ldf{Bs1)Mjai%6l1lLrjFSZ#`{em{lvWn5sIX6Ak>$e%1c!#k zDqEH~saRTGlV}<^AzBW9)af>N+LuOn_@9405B67b%@+Edk zS+z!|F%UKL;T&=yEE;Eb;i4YjkTZHJ8Z1^E7ElX70r?}cfawG!LWuccwDn&8+lfG5 zVMmq!3Z(7O)S9pxoU`Hh{}sduN`-v8Xx_s;JlZjd?VIUTB}S`7ky!A*lRJzlr0(&j zpJh=tl1QgoYx^#D)O(h8+^H`1LgS@31;75!X0!3qe?L&ms1;imNm0oc$%_%2H7?=N zAg(H$Y0Xg3+ky!nke^RI1~1GKr8b{eP0Wd@)jqHyVX4zy{wW;hS0tlxE--G3QAuTiv=qWjt%e@=diAqxUHXfy;)tof#34)xMwdLj-Z#lBl@ zs4Drwk!V9^?0DMkwnovo{p$7aV)<2?2xa+S7OeLhQVsl)%oL6Nx8bfg)F!?_L3sXb z_5G5_TWo($*=aAFm$H(2TyMPoRJ6~ta(8vJM{eW&Uj+A4 zh3wwv&cGH65K77RW(5Go6X^7k5kh9>%m%J|O6m`IE)}!%FWt!I6>RDfdN_xbyWi?>Jzm;!B& z_0G_}NTd1ajHy7Ro5e}NpCCBf6yD?B)ReRy!3bLky`H4ut%HtquR8Sg(GHmO?OTuN zGQ!PprfoYP8hs&ivi&R7Zw`c2@5rP~;`(;ix+~=Myx_1tZkb*B8luTK^-oOCV<7S` z{vv?Xo~CvinRB<&+(^2CW{p%KdXS>dMX~KelIC+(nSOgE)8Wkl7yTw+=v9a8I{D0O z8pO)H00NziuEcX8Sjo?h6N~*omG6j8(?>7ydP}Kt;~t8^$ruKl556ZaA87`xv4+iOG@|2LuS?YtPO-h(i^lp=t~qEZK{6!anc z79AMkSNePB*wOLa#Up$PFca(dkEiog3|)xO__UoG63%y{lCO-*x8)+B^d0GaFT1=H zfXHZ)In>TogbPg;Ca!A|4hC`p)A|9(zYHFpGd$87!cH8}4mH(tUY1ck9O4#EHp7?AU5mb z8p6!6#NZ;rjD!B?!fuFJHzJk`N=+|*o3wC1eNJ(5ILPgr%v@0d;OeiW-m zFT3f=25RnSx@-oOWxn~}Q#j0!*8*P0Wv(>8oU%N{ zmr={d;?wEFF)q9i{CF)rT5Hgr#3QA59K%F&TPRpmX)^v6B_*h>V}lrDiWdh5L}3nY zwSMSHmA>k=bJ`MpF}C*Lv1C&>`I%r#u?3lN7KKxu;x(To5Vao*@nn!_w`#lw_nzf>M~KlMFgRBF$sC&yeG#+=C5uA9yv1+s=dN(sgOU<<^Z6 zkX=_)TpTS4^v%FF=aAct<}c}U2s_y%?4^)8PDIJU7M0=Y!|Tts+;DYQUg20D(f z?sqMSUxtW~(o@^#zwuc9c zCcaUNg^v1ibF|5SvPo~azE9jHN#>z_J*+Q-Chihdr?*bEPNh7m3bB4l4w{rl)usqt z*!TonGdixYbUmofi1q3v#F_||BQ#0IvD88s$tEfkHXI9yfvdR6Azf{KYs|H?Rd99` zmu#fh5FTmWzh-3Fm#-50zjZUPLYvF<9B~TRJG|BfLg8FtW_z!M;~5Ts*P+Qw@^BGF z=#bmk?uy2>NE0Luc?--i-E1wY{w%h1*q|>Dz!Fhu2R_4)+03QI4wUP4JQGJH8Dj3e z7XlkkBoyDiV~BA24{qgiML0yP$U{hrD|`nNdW9nY>g?J<8AZcpf zKEf2vDy@qwiWF1`SgR=--<_`8g2ODt6eT>D&lrT(%}nFnAyx^ax-~n|=aL~e{#Bpt zO@~4WO+~H{FT|9t(H;hV0Vl%wbt-m3vfZ&#?HeC{R}8ROQ=XZUT4wZMR4Pz>P=vYU z9>_jop<94=2v(=0d?)s`N8Y@{M z-%wh6lO)-f5Q-g1)C}}sC8=jMqt0(D0`k!E=g>syvBvd+)*Qh+nMt3<1hU} zN#0oCFfOa57~E-Yw%z&3c;4)C0I4(Pe_t%1=J#*-eY5oQMovQchApKrBCQqlk|Q(7 zYmAAp$LsdG`KjU*xU{Jgiz%&wZF}7cCb56#fyN%|#(ID4m_ZlRGp?qqfbjC;H?*m` zlvj)v;BBzXixW2xWVG2gQUK>O(q5t?A!4d&J+wyD7yrc;=FlQE;HLzAq@==^Rp;-m z2!T~UEL$#d9{KQ}gHbv~u|=M4z$0(#bKU`-$Z*uzjysy!mwx9$i4}k`0M-3kz{Fc& z*$;=%WOW;R$F`%?(%1&C>)Jopi?+kE->!fgKnap;&+b~lKa(Xu_H@GIiR22vdv$c| zu~%h^gw)ssZYNbi;;0Ve?MP^(OdJkje0JBx+&#{wZOMexN+S0>pnng zeZcih8z5GkVj$DF#kNA|45?$r>rf(z1(sNI?qf+Cm7Jh5sn$ZV`yHygLX}0wR5?<< zQg@rOQ^Duk{nKpH;2|E)wt`l{`D-2P!3rSBOS18nTpG=O&<35$rapz39E41St4;CY zvHk)O`~r~THLp~~29Fd2#=m?!SzY1~!?Z^~kL$F*wG83vN8I$zy3LYB-s!c@KzPv=rdg18x`&-Av8qk`9OKBR**Hxe)_hSda|5?;tQ%QuX`??6{MD0(4D59tWT(?p`^Ua5 z=?{)`OAeZUG=?A#C9RXMxU(fpDZy!PqjTtZvoAS^0C9L5+|x#Lj?6WoR4rQLOdZ$) z);zH3QxjCiIsoesMUK)g8_t(wyeUjQg1CIR)O@n`A*!4CBK-b4sp*dD!x%`4u1K(9 zY3?Y#4tQJ> z5Y27AujRH9-`&BoTJVoo|91KiO{W(-XW6*{sv_v{X5qkqmMbwogs~rBLrmF7=W+Gy z$^?bX^*iQhj%GOgvwf2>97{5%kf4%~d6P~n==S_JubE#Hr_r~Sf|Xes7F8rQDy59e zRLarbL1Ov#IrNaH7I)@mzii@0@qS>V!3WDlD!_qzqfWe-mxDNjNS>clBq!Ju(bWSC zptW!#=n~5vTd!z5c*yV{#D5PA!^`f2C8VPv+Vgi{(2a+ooE_ZngJgK#5Vos}2}|EF z7EaBCl+Q1V?OH|SJ=79T+TP%38*87iPRB2EmwX4j#y1{!w!^>>Wb^&-7bc(`D10oU zog}$jY~ABx^+L!1dxckpWax;IH*UdaLp}TG2nn99)8NF>G(^!in7JbBK6t$lFAx-? zzK*7lB>2x#_-&Em1wssZL-;R#$0Rw|)hdR$;4p*K9&17EX4YV0snmRjXwS z-naY?l1#2MqV(d#?|)_KL#12?l@S&ryu&>-roW!@pW(lzGa&55goni(h5bc`ISa4v z3Km6^m6&AM#R&~Oa9($YOc6`(6Nc|Lx~JBMeqs=M@3T55Dks1!KOO2Rp+c!%ZgCYj zq-ZfepcXH~t@^$j4rTB7{VQ6a0Mixof`@YJcVn+5h+5_iyeLt=(4R~#h&_#~H;(%o zPAt$tWX%Jk@T}D;aS}2;hm%Pdl#xTE*cb{dqY$z8_r-aJX75@RX69ySo0C$dCshmg ziU<`XOYX^4i;l3hAaVRzy z^gsGYIZsl3Uw?sCnPv;SBaQ?QF43(+u)OV~eUOwz3w1OYa2h;hbME3*boZ5(?H5UC z_MJ6cO50czB{&kW6K0=cZYc1G?URZfDE>iG?zSDb^(^tV08YT`YC7<36sDf;5@jYM zV#RcMtPgyDT-tKRih-_FF z{3nfFBd+ygSG#qZGOESX9^^7Ve;&V(%}KkLjnxgwxLQ~s;nH8-O=PRo4SOuuhs|s% zf^33w@ikyH`l7CxN|b9y#NwhbHmkz+t|Zd+d86dSyvjhP6>Tl z|EmR@m3Rp~JvBLrI~YB-RF-&7q2}~7kql;v2K5e|(1wSt5z?D}Bj=59@DTw`&d*x_ zl{d`2ZrdX32@JmxP4vcy%!v1_`P+q2N9$atzcrYk(?~u~{FV`AAZG72rBf5*f6Q2ICqS#cNw~kVBkRqHa^LwyyNrHMTYf{QkB1D+A%Ez$xgem-+gE)*? z!c^)(ma(fl&JZJs&qd2rq1zSnz4m%%%r@ilt|(L ztfWZE!Ye1%$v`Sf2{Fr*jczu)C>em|sH##f1kuM`9x3&d5SzWJ(dF=6cHLpF%%XS@ zx!vrizheGTP+O`rlX~p^J|ulV*R9OmiPDqQQ-XZ{V}Hk_MTN%L08F{|#`4h1JlPhe zOB>mM$QTrjit$nK@5Hp;n9*f%1}CH$R&sJFTM&jmWp4onI|(U0y`lz0#PiGVZ~Gcj zwLhve&wU~F7+gt(Lo+7xK>+${AtlWcotT7+r(1dK~ zE2Tuak@bS{+#5v)#&cPkv<3Oe2wA zXKY>}b?uiK;s%kGS%aFD|8$fZ2%dcUfG)d){bq zvNKJ0Dh2rGQgYXIL0Y_?UL2Wd?G%O&^xUJ#)i7+mwJ z#0LR_sNxFMaSo#rhVFG%ph{gK?7CvCa$)d79+{QTn=9!uDV9&$dm?Y&M}Oi6R0=yR z^rH~USYM9?V!OFdbrn)?_bLMqx(LX`#IKX6+Gci88#-9y3#s)3Js4G@j-p-k9@Z7H zR+{$m-zE+M8i361IZ5IkMW5xS=N@-xXj4@rUM1+LhN4$J#=H`v3aJJ9q=6e%jBm7ebEIG zyt_VgdFTKGe?FVv@ENr2$zg?WU*&-SFvEDj(b06Sg?^ANrrc54h~v&dJmySqdEpz; zl(XTc;CVmh$(n?c_%bi5(v_H!FDlm`qv4XexI&AulmbKPYx7>#KK6N}e8`tnY ztOBE5ET>8@Vy`_`yMb+s1e%^vn>LU*?;HkAG9pdx>fKuNXtF-cKFP3@q{P($7m|?J z*FzOp7PK`qEalyQ4RT7p=%s))q&@Bj%^%eHfYT=Go|uXePMQbim{7iCeThY5c$z#l z4-s4R!y~1K6>%WGm{h@OeN08z*UxT#T9M|Clz&<;$8%Y~VRqU+l0fHK>5W?g*o_qc zfES7R{(DpEWup3PU%xLToFZX}SeWc4okPYytNB>OU7USCK^5I)6 zs9JPJRD4*WG6gAu(>u-DD@^wB?u(Z9I$=t7+seb)@n=_^uLCf z$q!~dwRRa@EzWk%F)mq{;Ix9B-7g^AOLAPZV&wYGh|`5LrW5pCmjkTWhQ!P(x0*Bj-53+rpQY0_<0P_N<(3zPoqTO%a))mDb4Ay-0y2nvyX} zA2#~;aT`hqUCAB}w`@Zl9;uhn4oPe>xYzJtO}yE-FtAW`r?wqXzIK}`vlf|2)tSWj z7xs|aW)KJ{>cp4iKfiA1WncCeC;%X^Yc54o)rIBDN~>_}jC8tnGL--xnDv?wXuMim zFKP!CES5IE>Pf9bSGWlSpXn+9X_#z9DJ>`={A>7N(@T_LfntDay%4bE5!N2bq8^vM z9mF#!YjmolXY&l#1YJ|)p%M_Z8KA*l>tZgo2B?!;+;3}bCro7%BiF;YNZ(n1F}I1^ zYF?z0)q#!}sI$wvoX-`O16dpXOHU#Jg=K!36p6#V36gaD1p_zpBM5tOpzN?7tHa*M2zj9*#sF~z@r`r*z?{o-dfXtcK^!+@><{SoaY=svAxZ3cQHrmuu6 zJ41f04!-dJ%`l1?zaSXD%?v9kg}47<3h?LO~)A*mpk zNtznR3If#TTJ-1iHO>L^gWD@;WoQ5<9pSx?`FrW>fHEQywED*o*iSgS;WBo{Y%Jsk zk51V|gqC8&uE)6neS}nfdM-|0?!{a}%na-k`7JkcYarUbnWi|VpPrd>&v$1=RzY!c-;!RQTVpGSQz0F)- zNhn>q4>ao~FOm-kapE+*9wzR1ppmX>$I4diK#1!_PNyv0%KFQvN&|8N*$_4;uq5X> z@&l0VnP!Rt6v}ipQ7J7@f4&y~MQ8>>uob$kn30S$R77-NbzB+@eU;Fp7wE*U9hKF; zuA1sySTLgZa5X)QLXfsN!rE-3w25<4@Vzwo1>in5M&F{GcPv@YG9!=NoaOtjBEC0v zcMAQe#hRsRi_Xk<9gAc7?`rRW;fA=LmxDmWM|a?wubhqf+ZY`hDxi}pA)@)Bui3AT zNwz}2EUcW{rSIyN8E8H7Om#sm#k*EI)Z7XeW+Ws9|9juj6|{8X4OJ2+n!UTbEnUGt*O2O3+&FB=1_VQcyJj+mH*55G;@25bLC(n7Gc#h zbBDdojiiFk)w4N}buJ#gB=n_lCl76_U)_Rzo|Bdg{rTD>IgDYgz;={-z5PySvu1OE zYws^M`X-4dgAG2{{+1KBAZ>lSgl7n~om$8#Y)Fy6xv8+N2tCO6C&sS|2 zud(nomgR!b2eYbF0t@cN#G*GNU6(P~h7sL3d% z1$>jqI-m>nt}s4*<1HI+I88ef?TiKBG*5eU`dEKjUxDXQF0oJ)hSgqOkVFdI%fD?h zX}b!@Nf%c%%omCzwIKtcLWyvf8fWoevaqot#d5j~ZNXqRvME{2q9mOv{oWJBY_RKw zA<5i#=g<>6D(%w!xW36Pamb5UU|bBk>=yX&{tj_dcg>;_DAsxM*O*wqUh;RF zpmRnf3~t8}d0dW{xyi|d$yW3(uPhnVN+Pq!{LIsHT75saKQedrhC)-|p5?fGyvQ>p^L&4@R_jU~#aI0f2zhI7gZ>Btkfaephx$C`EJ{+AKJX~ zY}#6f8xopzcBQ$CEjA)OJzf=7h{!z(74`7vq;F7CaaBo(T0bs`XxXl(OGA|)ce>11 zyjaf-@zbk=1dd)D)%w1yY*yPP;Tu7H_*8xLIK75d+Hg;mWC>uv30ArZpwL5!r?3&WF`a z8Wg32eeas&7kDHI2miXAkjJ2>Y z!@kq#G@~!8Jzs0^t%+fQ?0!+E7b@OjWZTN$=*N*4Cp;NlKsu< zI)rzUTBz%S=y)AP++9g(@Dsjy6}V7kWPhzB^f3TU@;Jk8?6l83DxsLF;m75CVoQ}Y zCK!2g5i3VLY;KyzXS*kRL|Gu9W(2tq1&aHP{YE6MrHHC-=_?4Sj(;L4ukEl z!`&l||1dqC{BrNJXUlP>HkB53GGS@0)sfEtE1`4PCSCBG+kslySxUb??ZqfWT&FbtW{8s{xR)tLM+hu;s15d1^%t^8PiR5bOh*uC~P6{41jmKWCCn+=c(M|1oWnG z$Y1%KZp)8m$xij`@Ov(wT;`&Zg^9fa7xX@e(!D1&5|$f<%)bCF0x7U!>LppzO[ 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.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 Date: Wed, 5 Jul 2023 16:42:49 -0400 Subject: [PATCH 2/7] Update news Adjusted some of the news I added previously. --- NEWS.md | 2 +- docs/src/news.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index e21147a1..cd06bdca 100644 --- a/NEWS.md +++ b/NEWS.md @@ -44,7 +44,7 @@ ## [v0.7.0](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.7.0) (March 28, 2022) - Added envelopes of activation functions: `xabsx`, `logcosh` -- Added `estimator_extrema`, `estimator_under`, and `estimator_over` functions for McCormick relaxations. +- Added variations of `estimator_extrema`, `estimator_under`, and `estimator_over` functions to EAGO for bilinear relaxations. - Moved various functions and related structures to new files. - Added `RelaxCache` structure to hold relaxed problem information. - Updated forward and reverse propagation. diff --git a/docs/src/news.md b/docs/src/news.md index ee7ed449..a26fcfd0 100644 --- a/docs/src/news.md +++ b/docs/src/news.md @@ -44,7 +44,7 @@ ## [v0.7.0](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.7.0) (March 28, 2022) - Added envelopes of activation functions: `xabsx`, `logcosh` -- Added `estimator_extrema`, `estimator_under`, and `estimator_over` functions for McCormick relaxations. +- Added variations of `estimator_extrema`, `estimator_under`, and `estimator_over` functions to EAGO for bilinear relaxations. - Moved various functions and related structures to new files. - Added `RelaxCache` structure to hold relaxed problem information. - Updated forward and reverse propagation. From 1eae9c0a604b8db5b56aed818746b44d5471c75c Mon Sep 17 00:00:00 2001 From: Dimitri Alston Date: Wed, 5 Jul 2023 17:12:40 -0400 Subject: [PATCH 3/7] Update README.md Added a badge for the PSOR Lab and changed some formatting related to the badges. Replaced images of equations with LaTeX. --- .gitignore | 3 +- README.md | 102 ++++++++++++++------------ docs/src/quick_start/quasiconvex.md | 2 +- docs/src/semiinfinite/semiinfinite.md | 2 +- images/OptForm.svg | 1 - images/ProcessFormulation.svg | 1 - images/math-code.js | 20 ----- 7 files changed, 57 insertions(+), 74 deletions(-) delete mode 100644 images/OptForm.svg delete mode 100644 images/ProcessFormulation.svg delete mode 100644 images/math-code.js diff --git a/.gitignore b/.gitignore index e4634270..3d28fc59 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ *.jl.mem *.mem *.cov -docs/build/ -.vscode \ No newline at end of file +docs/build/ \ No newline at end of file diff --git a/README.md b/README.md index d6541bdc..19b23db7 100644 --- a/README.md +++ b/README.md @@ -4,31 +4,42 @@ EAGO is an open-source development environment for **robust and global optimization** in Julia. -| **Documentation** | **Linux/OS/Windows** | **Persistent DOI** | -|:-----------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:| -| [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://PSORLab.github.io/EAGO.jl/stable) [![](https://img.shields.io/badge/docs-latest-blue.svg)](https://PSORLab.github.io/EAGO.jl/dev) | [![Build Status](https://github.com/PSORLab/EAGO.jl/workflows/CI/badge.svg?branch=master)](https://github.com/PSORLab/EAGO.jl/actions?query=workflow%3ACI) | [![DOI](https://zenodo.org/badge/108954118.svg)](https://zenodo.org/badge/latestdoi/108954118) | +| **PSOR Lab** | **Build Status** | +|:------------:|:-----------------------------------------------------------------------------------------------:| +| [![](https://img.shields.io/badge/Developed_by-PSOR_Lab-342674)](https://psor.uconn.edu/) | [![Build Status](https://github.com/PSORLab/EAGO.jl/workflows/CI/badge.svg?branch=master)](https://github.com/PSORLab/EAGO.jl/actions?query=workflow%3ACI) [![codecov](https://codecov.io/gh/PSORLab/EAGO.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/PSORLab/EAGO.jl)| -| **Coverage** | **Chat** | -|:------------:|:------------:| -| [![codecov](https://codecov.io/gh/PSORLab/EAGO.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/PSORLab/EAGO.jl) | [![Join the chat at https://gitter.im/EAGODevelopment](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/EAGODevelopment/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link) +| **Documentation** | **Persistent DOI** | +|:-----------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:| +| [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://PSORLab.github.io/EAGO.jl/stable) [![](https://img.shields.io/badge/docs-latest-blue.svg)](https://PSORLab.github.io/EAGO.jl/dev) | [![DOI](https://zenodo.org/badge/108954118.svg)](https://zenodo.org/badge/latestdoi/108954118) | + +| **Chat** | +|:------------:| +| [![Join the chat at https://gitter.im/EAGODevelopment](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/EAGODevelopment/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link) ## EAGO's Optimizer Capabilities EAGO is a deterministic global optimizer designed to address a wide variety of optimization problems, emphasizing nonlinear programs (NLPs), by propagating McCormick relaxations along the factorable structure of each expression in the NLP. Most operators supported by modern automatic differentiation (AD) packages (e.g., `+`, `sin`, `cosh`) are supported by EAGO and a number utilities for sanitizing native Julia code and generating relaxations on a wide variety of user-defined functions have been included. Currently, EAGO supports problems that have a priori variable bounds defined and have differentiable constraints. That is, problems should be specified in the generic form below: -

- +$$ +\begin{align*} +f^{\*} = & \min_{\mathbf y \in Y \subset \mathbb R^{n_{y}}} f(\mathbf y)\\ +{\rm s.t.} \\;\\; & \mathbf h(\mathbf y) = \mathbf 0\\ +& \mathbf g(\mathbf y) \leq \mathbf 0\\ +& Y = [\mathbf y^{\mathbf L}, \mathbf y^{\mathbf U}] \in \mathbb I \mathbb R^{n}\\ +& \qquad \mathbf y^{\mathbf L}, \mathbf y^{\mathbf U} \in \mathbb R^{n} +\end{align*} +$$ ## EAGO's Relaxations -For each nonlinear term, EAGO makes use of factorable representations to construct bounds and relaxations. In the case of `f(x) = x(x-5)sin(x)`, a list is generated and rules for constructing McCormick relaxations are used to formulate relaxations in the original decision space, *X* [[1](#references)]: +For each nonlinear term, EAGO makes use of factorable representations to construct bounds and relaxations. In the case of $f(x) = x (x - 5) \sin(x)$, a list is generated and rules for constructing McCormick relaxations are used to formulate relaxations in the original decision space, $X$ [[1](#references)]: -- *v*1 = *x* -- *v*2 = *v*1 - 5 -- *v*3 = sin(*v*1) -- *v*4 = *v*1*v*2 -- *v*5 = *v*4*v*3 -- f(x) = *v*5 +- $v_{1} = x$ +- $v_{2} = v_{1} - 5$ +- $v_{3} = \sin(v_{1})$ +- $v_{4} = v_{1} v_{2}$ +- $v_{5} = v_{4} v_{3}$ +- $f(x) = v_{5}$

@@ -39,8 +50,20 @@ Either these original relaxations, differentiable McCormick relaxations [[2](#re EAGO makes use of the JuMP algebraic modeling language to improve the user's experience in setting up optimization models. Consider the familiar "process" problem instance [[5](#references)]: -

- +$$ +\begin{align*} +& \max_{\mathbf x \in X} 0.063 x_{4} x_{7} - 5.04 x_{1} - 0.035 x_{2} - 10 x_{3} - 3.36 x_{2}\\ +{\rm s.t.} \\;\\; & x_{1} (1.12 + 0.13167 x_{8} - 0.00667 x_{8}^{2}) + x_{4} = 0\\ +& -0.001 x_{4} x_{9} x_{6} / (98 - x_{6}) + x_{3} = 0\\ +&-(1.098 x_{8} - 0.038 x_{8}^{2}) - 0.325 x_{6} + x_{7} = 0\\ +&-(x_{2} + x_{5}) / x_{1} + x_{8} = 0\\ +&-x_{1} + 1.22 x_{4} - x_{5} = 0\\ +&x_{9} + 0.222 x_{10} - 35.82 = 0\\ +&-3.0 x_{7} + x_{10} + 133.0 = 0\\ +& X = [10, 2000] \times [0, 16000] \times [0, 120] \times [0, 5000]\\ +& \qquad \times [0, 2000] \times [85, 93] \times [90,9 5] \times [3, 12] \times [1.2, 4] \times [145, 162] +\end{align*} +$$ This model can be formulated using JuMP code as: @@ -56,15 +79,15 @@ xU = [2000.0; 16000.0; 120.0; 5000.0; 2000.0; 93.0; 95.0; 12.0; 4.0; 162.0] @variable(m, xL[i] <= x[i=1:10] <= xU[i]) # Define nonlinear constraints -@NLconstraint(m, e1, -x[1]*(1.12+0.13167*x[8]-0.00667* (x[8])^2)+x[4] == 0.0) -@NLconstraint(m, e3, -0.001*x[4]*x[9]*x[6]/(98-x[6])+x[3] == 0.0) -@NLconstraint(m, e4, -(1.098*x[8]-0.038* (x[8])^2)-0.325*x[6]+x[7] == 57.425) -@NLconstraint(m, e5, -(x[2]+x[5])/x[1]+x[8] == 0.0) +@NLconstraint(m, e1, -x[1]*(1.12 + 0.13167*x[8] - 0.00667*(x[8])^2) + x[4] == 0.0) +@NLconstraint(m, e3, -0.001*x[4]*x[9]*x[6]/(98.0 - x[6]) + x[3] == 0.0) +@NLconstraint(m, e4, -(1.098*x[8] - 0.038*(x[8])^2) - 0.325*x[6] + x[7] == 57.425) +@NLconstraint(m, e5, -(x[2] + x[5])/x[1] + x[8] == 0.0) # Define linear constraints -@constraint(m, e2, -x[1]+1.22*x[4]-x[5] == 0.0) -@constraint(m, e6, x[9]+0.222*x[10] == 35.82) -@constraint(m, e7, -3*x[7]+x[10] == -133.0) +@constraint(m, e2, -x[1] + 1.22*x[4] - x[5] == 0.0) +@constraint(m, e6, x[9] + 0.222*x[10] == 35.82) +@constraint(m, e7, -3.0*x[7] + x[10] == -133.0) # Define nonlinear objective @NLobjective(m, Max, 0.063*x[4]*x[7] - 5.04*x[1] - 0.035*x[2] - 10*x[3] - 3.36*x[5]) @@ -72,22 +95,6 @@ xU = [2000.0; 16000.0; 120.0; 5000.0; 2000.0; 93.0; 95.0; 12.0; 4.0; 162.0] # Solve the optimization problem JuMP.optimize!(m) ``` - Special handling has been included for linear/quadratic functions defined using the `@constraint` macro in JuMP and these can generally be expected to perform better than specifying quadratic or linear terms with the `@NLconstraint` macro. @@ -115,12 +122,11 @@ The EAGO package has numerous features: a solver accessible from JuMP/MathOptInt - Models, nodes, expressions, constraints, and operators are now compatible with MOI. - Added logic and comparison operators to `EAGO.OperatorRegistry`. -For a full list of EAGO release news, click [here](https://psorlab.github.io/EAGO.jl/stable/news/). +For a full list of EAGO release news, click [here](https://github.com/PSORLab/EAGO.jl/blob/master/NEWS.md). ## Installing EAGO -EAGO is a registered Julia package and it can be installed using the Julia package manager. -From the Julia REPL, type `]` to enter the Package manager (Pkg) mode and run the following command: +EAGO is a registered Julia package and it can be installed using the Julia package manager. From the Julia REPL, type `]` to enter the Package manager (Pkg) mode and run the following command: ```jldoctest pkg> add EAGO @@ -132,8 +138,7 @@ Currently, EAGO is compatible with version 1.12 of JuMP. This allows a replicati pkg> add JuMP ``` -EAGO v0.8.1 is the current tagged version and requires Julia 1.6+ for full functionality (however Julia 1.0+ versions support partial functionality). Use with version 1.8 is recommended as the majority of in-house testing has occurred using this version of Julia. The user is directed to the [High-Performance Configuration](https://psorlab.github.io/EAGO.jl/optimizer/high_performance/) for instructions on how to install a high performance version of EAGO (rather than the basic entirely open-source version). -If any issues are encountered when loading EAGO (or when using it), please submit an issue using the GitHub [issue tracker](https://github.com/PSORLab/EAGO.jl/issues). +EAGO v0.8.1 is the current tagged version and requires Julia 1.6+ for full functionality (however Julia 1.0+ versions support partial functionality). Use with version 1.8 is recommended as the majority of in-house testing has occurred using this version of Julia. The user is directed to the [High-Performance Configuration](https://psorlab.github.io/EAGO.jl/optimizer/high_performance/) for instructions on how to install a high performance version of EAGO (rather than the basic entirely open-source version). If any issues are encountered when loading EAGO (or when using it), please submit an issue using the GitHub [issue tracker](https://github.com/PSORLab/EAGO.jl/issues). ## Bug Reporting, Support, and Feature Requests @@ -155,12 +160,14 @@ Please report bugs or feature requests by opening an issue using the GitHub [iss ## Citing EAGO Please cite the following paper when using EAGO. In plain text form this is: + ``` M. E. Wilhelm & M. D. Stuber (2022) EAGO.jl: easy advanced global optimization in Julia, Optimization Methods and Software, 37:2, 425-450, DOI: 10.1080/10556788.2020.1786566 ``` A BibTeX entry is given below and a corresponding .bib file is given in citation.bib. + ```bibtex @article{doi:10.1080/10556788.2020.1786566, author = {M. E. Wilhelm and M. D. Stuber}, @@ -179,10 +186,9 @@ eprint = {https://doi.org/10.1080/10556788.2020.1786566} ## Related Packages -- [ValidatedNumerics.jl](https://github.com/JuliaIntervals/ValidatedNumerics.jl): A Julia library for validated interval calculations, including basic interval extensions, constraint programming, and interval contractors +- [ValidatedNumerics.jl](https://github.com/JuliaIntervals/ValidatedNumerics.jl): A Julia library for validated interval calculations, including basic interval extensions, constraint programming, and interval contractors. - [MAiNGO](http://swmath.org/software/27878): An open-source mixed-integer nonlinear programming package in C++ that utilizes MC++ for relaxations. -- [MC++](https://omega-icl.github.io/mcpp/): A mature McCormick relaxation package in C++ that also includes McCormick-Taylor, Chebyshev -Polyhedral and Ellipsoidal arithmetics. +- [MC++](https://github.com/coin-or/MCpp): A mature McCormick relaxation package in C++ that also includes McCormick-Taylor, Chebyshev Polyhedral, and Ellipsoidal arithmetics. ## References diff --git a/docs/src/quick_start/quasiconvex.md b/docs/src/quick_start/quasiconvex.md index c6aee502..e26f093e 100644 --- a/docs/src/quick_start/quasiconvex.md +++ b/docs/src/quick_start/quasiconvex.md @@ -13,7 +13,7 @@ f^{*} = & \min_{\mathbf y \in Y} f(\mathbf y)\\ & \sum_{i = 1}^{5} y_{i}^{2} - 0.5\pi \leq 0\\ & -\bigg(\frac{1}{2} y_{1}^{2} + \frac{1}{2} y_{2}^{2} + 2 y_{1} y_{2} + 4 y_{1} y_{3} + 2 y_{2} y_{3} \bigg) \leq 0\\ & -y_{1}^{2} - 6 y_{1} y_{2} - 2 y_{2}^{2} + \cos (y_{1}) + \pi \leq 0\\ -& Y = [0,5]^{5} +& Y = [0, 5]^{5} \end{aligned} ``` diff --git a/docs/src/semiinfinite/semiinfinite.md b/docs/src/semiinfinite/semiinfinite.md index 8f8de666..5bcc30fc 100644 --- a/docs/src/semiinfinite/semiinfinite.md +++ b/docs/src/semiinfinite/semiinfinite.md @@ -31,7 +31,7 @@ using EAGO, JuMP # Define semi-infinite program f(x) = (1/3)*x[1]^2 + x[2]^2 + x[1]/2 -gSIP(x,p) = (1.0 - (x[1]^2)*(p[1]^2))^2 - x[1]*p[1]^2 - x[2]^2 + x[2] +gSIP(x, p) = (1.0 - (x[1]^2)*(p[1]^2))^2 - x[1]*p[1]^2 - x[2]^2 + x[2] x_l = Float64[-1000.0, -1000.0] x_u = Float64[1000.0, 1000.0] diff --git a/images/OptForm.svg b/images/OptForm.svg deleted file mode 100644 index a49de3a9..00000000 --- a/images/OptForm.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/ProcessFormulation.svg b/images/ProcessFormulation.svg deleted file mode 100644 index 6f78380f..00000000 --- a/images/ProcessFormulation.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/math-code.js b/images/math-code.js deleted file mode 100644 index a4358069..00000000 --- a/images/math-code.js +++ /dev/null @@ -1,20 +0,0 @@ -(function() { - var i, text, code, codes = document.getElementsByTagName('code'); - for (i = 0; i < codes.length;) { - code = codes[i]; - if (code.parentNode.tagName !== 'PRE' && code.childElementCount === 0) { - text = code.textContent; - if (/^\$[^$]/.test(text) && /[^$]\$$/.test(text)) { - text = text.replace(/^\$/, '\\(').replace(/\$$/, '\\)'); - code.textContent = text; - } - if (/^\\\((.|\s)+\\\)$/.test(text) || /^\\\[(.|\s)+\\\]$/.test(text) || - /^\$(.|\s)+\$$/.test(text) || - /^\\begin\{([^}]+)\}(.|\s)+\\end\{[^}]+\}$/.test(text)) { - code.outerHTML = code.innerHTML; // remove - continue; - } - } - i++; - } -})(); From 278848624d9576d39760ff2edfc4e7430e9ec5c0 Mon Sep 17 00:00:00 2001 From: Dimitri Alston Date: Mon, 6 Nov 2023 15:46:04 -0500 Subject: [PATCH 4/7] Update documentation and examples --- README.md | 48 ++++++++-------- docs/Project.toml | 2 +- docs/make.jl | 55 ++++++++++--------- docs/src/cite.md | 4 +- .../guidelines.md => custom_guidelines.md} | 0 docs/src/dev/api_functions.md | 6 ++ docs/src/dev/api_types.md | 6 ++ docs/src/dev/contributing.md | 4 +- .../src/{quick_start => examples}/alpha_bb.md | 8 +-- .../{quick_start => examples}/explicit_ann.md | 10 ++-- .../{quick_start => examples}/interval_bb.md | 2 +- .../{quick_start => examples}/quasiconvex.md | 18 +++--- docs/src/index.md | 6 +- docs/src/mccormick/overview.md | 4 +- docs/src/semiinfinite/semiinfinite.md | 26 ++++----- src/eago_optimizer/types/global_optimizer.jl | 2 +- 16 files changed, 105 insertions(+), 96 deletions(-) rename docs/src/{quick_start/guidelines.md => custom_guidelines.md} (100%) create mode 100644 docs/src/dev/api_functions.md create mode 100644 docs/src/dev/api_types.md rename docs/src/{quick_start => examples}/alpha_bb.md (94%) rename docs/src/{quick_start => examples}/explicit_ann.md (78%) rename docs/src/{quick_start => examples}/interval_bb.md (98%) rename docs/src/{quick_start => examples}/quasiconvex.md (94%) diff --git a/README.md b/README.md index 19b23db7..b915b1c9 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,10 @@ EAGO is a deterministic global optimizer designed to address a wide variety of o $$ \begin{align*} -f^{\*} = & \min_{\mathbf y \in Y \subset \mathbb R^{n_{y}}} f(\mathbf y)\\ -{\rm s.t.} \\;\\; & \mathbf h(\mathbf y) = \mathbf 0\\ -& \mathbf g(\mathbf y) \leq \mathbf 0\\ -& Y = [\mathbf y^{\mathbf L}, \mathbf y^{\mathbf U}] \in \mathbb I \mathbb R^{n}\\ +f^{\*} = & \min_{\mathbf y \in Y \subset \mathbb R^{n_{y}}} f(\mathbf y) \\ +{\rm s.t.} \\;\\; & \mathbf h(\mathbf y) = \mathbf 0 \\ +& \mathbf g(\mathbf y) \leq \mathbf 0 \\ +& Y = [\mathbf y^{\mathbf L}, \mathbf y^{\mathbf U}] \in \mathbb{IR}^{n} \\ & \qquad \mathbf y^{\mathbf L}, \mathbf y^{\mathbf U} \in \mathbb R^{n} \end{align*} $$ @@ -52,15 +52,15 @@ EAGO makes use of the JuMP algebraic modeling language to improve the user's exp $$ \begin{align*} -& \max_{\mathbf x \in X} 0.063 x_{4} x_{7} - 5.04 x_{1} - 0.035 x_{2} - 10 x_{3} - 3.36 x_{2}\\ -{\rm s.t.} \\;\\; & x_{1} (1.12 + 0.13167 x_{8} - 0.00667 x_{8}^{2}) + x_{4} = 0\\ -& -0.001 x_{4} x_{9} x_{6} / (98 - x_{6}) + x_{3} = 0\\ -&-(1.098 x_{8} - 0.038 x_{8}^{2}) - 0.325 x_{6} + x_{7} = 0\\ -&-(x_{2} + x_{5}) / x_{1} + x_{8} = 0\\ -&-x_{1} + 1.22 x_{4} - x_{5} = 0\\ -&x_{9} + 0.222 x_{10} - 35.82 = 0\\ -&-3.0 x_{7} + x_{10} + 133.0 = 0\\ -& X = [10, 2000] \times [0, 16000] \times [0, 120] \times [0, 5000]\\ +& \max_{\mathbf x \in X} 0.063 x_{4} x_{7} - 5.04 x_{1} - 0.035 x_{2} - 10 x_{3} - 3.36 x_{2} \\ +{\rm s.t.} \\;\\; & x_{1} (1.12 + 0.13167 x_{8} - 0.00667 x_{8}^{2}) + x_{4} = 0 \\ +& -0.001 x_{4} x_{9} x_{6} / (98 - x_{6}) + x_{3} = 0 \\ +& -(1.098 x_{8} - 0.038 x_{8}^{2}) - 0.325 x_{6} + x_{7} = 0 \\ +& -(x_{2} + x_{5}) / x_{1} + x_{8} = 0 \\ +& -x_{1} + 1.22 x_{4} - x_{5} = 0 \\ +& x_{9} + 0.222 x_{10} - 35.82 = 0 \\ +& -3.0 x_{7} + x_{10} + 133.0 = 0 \\ +& X = [10, 2000] \times [0, 16000] \times [0, 120] \times [0, 5000] \\ & \qquad \times [0, 2000] \times [85, 93] \times [90,9 5] \times [3, 12] \times [1.2, 4] \times [145, 162] \end{align*} $$ @@ -162,15 +162,15 @@ Please report bugs or feature requests by opening an issue using the GitHub [iss Please cite the following paper when using EAGO. In plain text form this is: ``` -M. E. Wilhelm & M. D. Stuber (2022) EAGO.jl: easy advanced global optimization in Julia, -Optimization Methods and Software, 37:2, 425-450, DOI: 10.1080/10556788.2020.1786566 +Wilhelm, M.E. and Stuber, M.D. EAGO.jl: easy advanced global optimization in Julia. +Optimization Methods and Software. 37(2): 425-450 (2022). DOI: 10.1080/10556788.2020.1786566 ``` A BibTeX entry is given below and a corresponding .bib file is given in citation.bib. ```bibtex @article{doi:10.1080/10556788.2020.1786566, -author = {M. E. Wilhelm and M. D. Stuber}, +author = {Wilhelm, M.E. and Stuber, M.D.}, title = {EAGO.jl: easy advanced global optimization in Julia}, journal = {Optimization Methods and Software}, volume = {37}, @@ -186,14 +186,14 @@ eprint = {https://doi.org/10.1080/10556788.2020.1786566} ## Related Packages -- [ValidatedNumerics.jl](https://github.com/JuliaIntervals/ValidatedNumerics.jl): A Julia library for validated interval calculations, including basic interval extensions, constraint programming, and interval contractors. -- [MAiNGO](http://swmath.org/software/27878): An open-source mixed-integer nonlinear programming package in C++ that utilizes MC++ for relaxations. -- [MC++](https://github.com/coin-or/MCpp): A mature McCormick relaxation package in C++ that also includes McCormick-Taylor, Chebyshev Polyhedral, and Ellipsoidal arithmetics. +- [ValidatedNumerics.jl](https://github.com/JuliaIntervals/ValidatedNumerics.jl): A Julia library for validated interval calculations, including basic interval extensions, constraint programming, and interval contractors +- [MAiNGO](https://avt-svt.pages.rwth-aachen.de/public/maingo/): An open-source mixed-integer nonlinear programming package in C++ that utilizes MC++ for relaxations +- [MC++](https://github.com/coin-or/MCpp): A mature McCormick relaxation package in C++ that also includes McCormick-Taylor, Chebyshev Polyhedral, and Ellipsoidal arithmetics ## References -1. A. Mitsos, B. Chachuat, and P. I. Barton. **McCormick-based relaxations of algorithms.** *SIAM Journal on Optimization*, 20(2):573–601, 2009. -2. K.A. Khan, HAJ Watson, P.I. Barton. **Differentiable McCormick relaxations.** *Journal of Global Optimization*, 67(4):687-729 (2017). -3. Stuber, M.D., Scott, J.K., Barton, P.I.: **Convex and concave relaxations of implicit functions.** *Optim. Methods Softw.* 30(3), 424–460 (2015) -4. A., Wechsung JK Scott, HAJ Watson, and PI Barton. **Reverse propagation of McCormick relaxations.** *Journal of Global Optimization* 63(1):1-36 (2015). -5. Bracken, Jerome and McCormick, Garth P. **Selected Applications of Nonlinear Programming**, John Wiley and Sons, New York, 1968. +1. Mitsos, A., Chachuat, B., and Barton, P.I. **McCormick-based relaxations of algorithms.** *SIAM Journal on Optimization*. 20(2): 573–601 (2009). +2. Khan, K.A., Watson, H.A.J., and Barton, P.I. **Differentiable McCormick relaxations.** *Journal of Global Optimization*. 67(4): 687-729 (2017). +3. Stuber, M.D., Scott, J.K., and Barton, P.I.: **Convex and concave relaxations of implicit functions.** *Optimization Methods and Software* 30(3): 424–460 (2015). +4. Wechsung, A., Scott, J.K., Watson, H.A.J., and Barton, P.I. **Reverse propagation of McCormick relaxations.** *Journal of Global Optimization* 63(1): 1-36 (2015). +5. Bracken, J., and McCormick, G.P. *Selected Applications of Nonlinear Programming.* John Wiley and Sons, New York (1968). \ No newline at end of file diff --git a/docs/Project.toml b/docs/Project.toml index 26be57ee..e325b26a 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -9,5 +9,5 @@ McCormick = "53c679d3-6890-5091-8386-c291e8c8aaa1" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" [compat] -Documenter = "0.27.9, 0.28" JuMP = "1.12" +Documenter = "~1" diff --git a/docs/make.jl b/docs/make.jl index e8cf2c0b..7daccc80 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -19,11 +19,10 @@ import EAGO: ExtensionType, Evaluator, variable_dbbt!, import EAGO.Script: dag_flattening!, register_substitution!, Template_Graph, Template_Node, scrub, scrub!, flatten_expression! -const MOI = MathOptInterface - @info "Making documentation..." makedocs(modules = [EAGO, McCormick], doctest = false, + warnonly = [:docs_block, :missing_docs], format = Documenter.HTML( prettyurls = get(ENV, "CI", nothing) == "true", canonical = "https://PSORLab.github.io/EAGO.jl/stable/", @@ -33,33 +32,35 @@ makedocs(modules = [EAGO, McCormick], authors = "Matthew Wilhelm, Robert Gottlieb, Dimitri Alston, and Matthew Stuber", sitename = "EAGO.jl", pages = Any["Introduction" => "index.md", - "Quick Start" => Any["quick_start/qs_landing.md", - "quick_start/guidelines.md", - "quick_start/explicit_ann.md", - "quick_start/interval_bb.md", - "quick_start/quasiconvex.md", - "quick_start/alpha_bb.md" - ], - "McCormick Operator Library" => Any["mccormick/overview.md", - "mccormick/usage.md", - "mccormick/operators.md", - "mccormick/type.md", - "mccormick/implicit.md" - ], - "Optimizer" => Any["optimizer/optimizer.md", - "optimizer/bnb_back.md", - "optimizer/relax_back.md", - "optimizer/domain_reduction.md", - "optimizer/high_performance.md", - "optimizer/udf_utilities.md" - ], - "Semi-Infinite Programming" => "semiinfinite/semiinfinite.md", - "Contributing to EAGO" => Any["dev/contributing.md", - "dev/future.md" + "Manual" => Any["Optimizer" => Any["optimizer/optimizer.md", + "optimizer/bnb_back.md", + "optimizer/relax_back.md", + "optimizer/domain_reduction.md", + "optimizer/high_performance.md", + "optimizer/udf_utilities.md" ], + "McCormick.jl" => Any["mccormick/overview.md", + "mccormick/usage.md", + "mccormick/operators.md", + "mccormick/type.md", + "mccormick/implicit.md" + ], + "Semi-Infinite Programming" => "semiinfinite/semiinfinite.md", + ], + "Customization" => "custom_guidelines.md", + "Examples" => Any["examples/explicit_ann.md", + "examples/interval_bb.md", + "examples/quasiconvex.md", + "examples/alpha_bb.md" + ], + "API Reference" => Any["dev/api_types.md", + "dev/api_functions.md" + ], + "Contributing" => "dev/contributing.md", + "News" => "news.md", "Citing EAGO" => "cite.md", - "News" => "news.md", - "References" => "ref.md"] + "References" => "ref.md" + ] ) @info "Deploying documentation..." diff --git a/docs/src/cite.md b/docs/src/cite.md index 26ebc0ca..a3fb1a44 100644 --- a/docs/src/cite.md +++ b/docs/src/cite.md @@ -4,6 +4,6 @@ Please cite the following paper when using EAGO.jl: ``` -M. E. Wilhelm & M. D. Stuber (2022) EAGO.jl: easy advanced global optimization in Julia, -Optimization Methods and Software, 37:2, 425-450, DOI: 10.1080/10556788.2020.1786566 +Wilhelm, M.E. and Stuber, M.D. EAGO.jl: easy advanced global optimization in Julia. +Optimization Methods and Software. 37(2): 425-450 (2022). DOI: 10.1080/10556788.2020.1786566 ``` diff --git a/docs/src/quick_start/guidelines.md b/docs/src/custom_guidelines.md similarity index 100% rename from docs/src/quick_start/guidelines.md rename to docs/src/custom_guidelines.md diff --git a/docs/src/dev/api_functions.md b/docs/src/dev/api_functions.md new file mode 100644 index 00000000..aca52cd6 --- /dev/null +++ b/docs/src/dev/api_functions.md @@ -0,0 +1,6 @@ +# Functions + +```@autodocs; canonical=false +Modules = [EAGO] +Order = [:function] +``` \ No newline at end of file diff --git a/docs/src/dev/api_types.md b/docs/src/dev/api_types.md new file mode 100644 index 00000000..0709be1c --- /dev/null +++ b/docs/src/dev/api_types.md @@ -0,0 +1,6 @@ +# Types + +```@autodocs; canonical=false +Modules = [EAGO] +Order = [:type] +``` \ No newline at end of file diff --git a/docs/src/dev/contributing.md b/docs/src/dev/contributing.md index 2cd0aa95..fa5fc196 100644 --- a/docs/src/dev/contributing.md +++ b/docs/src/dev/contributing.md @@ -1,4 +1,4 @@ -# How to Contribute +# How to Contribute to EAGO We're always happy to welcome work with additional collaborators and contributors. One of the easy ways for newcomers to contribute is by adding additional McCormick relaxations. @@ -10,4 +10,4 @@ Please direct technical issues and/or bugs to the active developers: - [Robert Gottlieb](https://psor.uconn.edu/person/robert-gottlieb/) - [Dimitri Alston](https://psor.uconn.edu/person/dimitri-alston/) -All other questions should be directed to [Prof. Stuber](https://chemical-biomolecular.engr.uconn.edu/person/matthew-stuber/). +All other questions should be directed to [Prof. Stuber](https://chemical-biomolecular.engr.uconn.edu/people/faculty/stuber-matthew/). diff --git a/docs/src/quick_start/alpha_bb.md b/docs/src/examples/alpha_bb.md similarity index 94% rename from docs/src/quick_start/alpha_bb.md rename to docs/src/examples/alpha_bb.md index b02bac61..e586170b 100644 --- a/docs/src/quick_start/alpha_bb.md +++ b/docs/src/examples/alpha_bb.md @@ -8,9 +8,9 @@ In this example, we will demonstrate the use of a user-defined lower-bounding pr ```math \begin{aligned} -& \min_{\mathbf x \in \mathbb R^{2}} \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{f} \mathbf x + \mathbf c_{f}^{\rm T} \mathbf x\\ -{\rm s.t.} \;\; & g_{1}(\mathbf x)= \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{g_{1}}\mathbf x + \mathbf c_{g_{1}}^{\rm T} \mathbf x \leq 0\\ -& g_{2}(\mathbf x) = \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{g_{2}} \mathbf x + \mathbf c_{g_{2}}^{\rm T} \mathbf x \leq 0\\ +& \min_{\mathbf x \in \mathbb{IR}^{2}} \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{f} \mathbf x + \mathbf c_{f}^{\rm T} \mathbf x \\ +{\rm s.t.} \; \; & g_{1}(\mathbf x) = \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{g_{1}}\mathbf x + \mathbf c_{g_{1}}^{\rm T} \mathbf x \leq 0 \\ +& g_{2}(\mathbf x) = \frac{1}{2} \mathbf x^{\rm T} \mathbf Q_{g_{2}} \mathbf x + \mathbf c_{g_{2}}^{\rm T} \mathbf x \leq 0 \\ \end{aligned} ``` @@ -117,7 +117,7 @@ end !!! note - By default, EAGO solves the epigraph reformulation of your original problem, which increases the original problem dimensionality by +1 with the introduction of an auxiliary variable. When defining custom routines (such as the lower-bounding problem here) that are intended to work nicely with default EAGO routines (such as preprocessing), the user must account for the *new* dimensionality of the problem. In the code above, we wish to access the information of the specific B&B node and define an optimization problem based on that information. However, in this example, the node has information for 3 variables (the original 2 plus 1 for the auxiliary variable appended to the original variable vector) as ``(x_{1}, x_{2}, \eta)``. The lower-bounding problem was defined to optimize the relaxed problem with respect to the original 2 decision variables. When storing the results of this subproblem to the current B&B node, it is important to take care to store the information at the appropriate indices and not inadvertently redefine the problem dimensionality (i.e., by simply storing the optimization solution as the `lower_solution` of the current node). For problems that are defined to only branch on a subset of the original variables, the optimizer has a member `_sol_to_branch_map` that carries the mapping between the indices of the original variables to those of the variables being branched on. See the [Advanced-Use Example 1](@ref) to see how this is done. + By default, EAGO solves the epigraph reformulation of your original problem, which increases the original problem dimensionality by +1 with the introduction of an auxiliary variable. When defining custom routines (such as the lower-bounding problem here) that are intended to work nicely with default EAGO routines (such as preprocessing), the user must account for the *new* dimensionality of the problem. In the code above, we wish to access the information of the specific B&B node and define an optimization problem based on that information. However, in this example, the node has information for 3 variables (the original 2 plus 1 for the auxiliary variable appended to the original variable vector) as ``(x_{1}, x_{2}, \eta)``. The lower-bounding problem was defined to optimize the relaxed problem with respect to the original 2 decision variables. When storing the results of this subproblem to the current B&B node, it is important to take care to store the information at the appropriate indices and not inadvertently redefine the problem dimensionality (i.e., by simply storing the optimization solution as the `lower_solution` of the current node). For problems that are defined to only branch on a subset of the original variables, the optimizer has a member `_sol_to_branch_map` that carries the mapping between the indices of the original variables to those of the variables being branched on. Visit our [quasiconvex example](@ref "Advanced-Use Example 1") to see how this is done. ## (Optional) Turn Off Processing Routines diff --git a/docs/src/quick_start/explicit_ann.md b/docs/src/examples/explicit_ann.md similarity index 78% rename from docs/src/quick_start/explicit_ann.md rename to docs/src/examples/explicit_ann.md index 909dd7bd..a5e7b7b6 100644 --- a/docs/src/quick_start/explicit_ann.md +++ b/docs/src/examples/explicit_ann.md @@ -4,11 +4,11 @@ This example is also provided [here as a Jupyter Notebook](https://github.com/PS ### Solving an ANN to Optimality in EAGO -In [[1](#References),[2](#References)], a surrogate artificial neural network (ANN) model of bioreactor productivity was constructed by fitting results from computationally expensive computational fluid dynamics (CFD) simulations. The authors then optimized this surrogate model to obtain ideal processing conditions. The optimization problem is given by: +In [[1](#References), [2](#References)], a surrogate artificial neural network (ANN) model of bioreactor productivity was constructed by fitting results from computationally expensive computational fluid dynamics (CFD) simulations. The authors then optimized this surrogate model to obtain ideal processing conditions. The optimization problem is given by: ```math \begin{aligned} -\max_{\mathbf x \in X} B_{2} + \sum_{r = 1}^{3} W_{2,r} \frac{2}{1 + \exp (-2y_{r} + B_{1,r})} \;\; {\rm where} \;\; y_{r} = \sum_{i = 1}^{8} W_{1,ir} x_{i} +\max_{\mathbf x \in X} B_{2} + \sum_{r = 1}^{3} W_{2,r} \frac{2}{1 + \exp (-2y_{r} + B_{1,r})} \; \; {\rm where} \; \; y_{r} = \sum_{i = 1}^{8} W_{1,ir} x_{i} \end{aligned} ``` @@ -35,12 +35,12 @@ B2 = -0.46 # Variable bounds (Used to scale variables after optimization) xLBD = [0.623, 0.093, 0.259, 6.56, 1114.0, 0.013, 0.127, 0.004] -xUBD = [5.89, 0.5, 1.0, 90.0, 25000.0, 0.149, 0.889, 0.049]; +xUBD = [5.89, 0.5, 1.0, 90.0, 25000.0, 0.149, 0.889, 0.049] ``` ## Construct the JuMP Model and Optimize -We now formulate the problem using standard JuMP [[3](#References)] syntax and optimize it. Note that we are forming an NLexpression object to handle the summation term to keep the code visually simple, but this could be placed directly in the JuMP [`@NLobjective`](https://jump.dev/JuMP.jl/stable/api/JuMP/#@NLobjective) expression instead. +We now formulate the problem using standard JuMP [[3](#References)] syntax and optimize it. Note that we are using the [`@NLexpression`](https://jump.dev/JuMP.jl/stable/api/JuMP/#JuMP.@NLexpression) macro to handle the summation term to keep the code visually simple, but this could be placed directly in the [`@NLobjective`](https://jump.dev/JuMP.jl/stable/api/JuMP/#JuMP.@NLobjective) macro instead. ```julia # Model construction @@ -66,7 +66,7 @@ status_prim = JuMP.primal_status(model) println("EAGO terminated with a status of $status_term and a result code of $status_prim.") println("The optimal value is: $(round(fval, digits=5)).") println("The solution found is $(round.(xsol, digits=3)).") -println("") +println(" ") # Rescale values back to physical space rescaled_fval = ((fval + 1.0)/2.0)*0.07 diff --git a/docs/src/quick_start/interval_bb.md b/docs/src/examples/interval_bb.md similarity index 98% rename from docs/src/quick_start/interval_bb.md rename to docs/src/examples/interval_bb.md index 5ad6e60e..55b0eb44 100644 --- a/docs/src/quick_start/interval_bb.md +++ b/docs/src/examples/interval_bb.md @@ -10,7 +10,7 @@ In this example, we'll forgo extensive integration into the [`Optimizer`](@ref) ```math \begin{aligned} -& \min_{\mathbf x \in X} \;\; \sin(x_{1}) x_{2}^{2} - \cos(x_{3}) / x_{4}\\ +& \min_{\mathbf x \in X} \; \; \sin(x_{1}) x_{2}^{2} - \cos(x_{3}) / x_{4} \\ & X = [-10, 10] \times [-1, 1] \times [-10, 10] \times [2, 20]. \end{aligned} ``` diff --git a/docs/src/quick_start/quasiconvex.md b/docs/src/examples/quasiconvex.md similarity index 94% rename from docs/src/quick_start/quasiconvex.md rename to docs/src/examples/quasiconvex.md index e26f093e..5cbf0390 100644 --- a/docs/src/quick_start/quasiconvex.md +++ b/docs/src/examples/quasiconvex.md @@ -8,11 +8,11 @@ In this example, we'll adapt EAGO to implement the bisection-based algorithm use ```math \begin{aligned} -f^{*} = & \min_{\mathbf y \in Y} f(\mathbf y)\\ -{\rm s.t.} \;\; & \sum_{i = 1}^{5} i \cdot y_{i} - 5 = 0\\ -& \sum_{i = 1}^{5} y_{i}^{2} - 0.5\pi \leq 0\\ -& -\bigg(\frac{1}{2} y_{1}^{2} + \frac{1}{2} y_{2}^{2} + 2 y_{1} y_{2} + 4 y_{1} y_{3} + 2 y_{2} y_{3} \bigg) \leq 0\\ -& -y_{1}^{2} - 6 y_{1} y_{2} - 2 y_{2}^{2} + \cos (y_{1}) + \pi \leq 0\\ +f^{*} = & \min_{\mathbf y \in Y} f(\mathbf y) \\ +{\rm s.t.} \; \; & \sum_{i = 1}^{5} i \cdot y_{i} - 5 = 0 \\ +& \sum_{i = 1}^{5} y_{i}^{2} - 0.5 \pi \leq 0 \\ +& -\bigg(\frac{1}{2} y_{1}^{2} + \frac{1}{2} y_{2}^{2} + 2 y_{1} y_{2} + 4 y_{1} y_{3} + 2 y_{2} y_{3} \bigg) \leq 0 \\ +& -y_{1}^{2} - 6 y_{1} y_{2} - 2 y_{2}^{2} + \cos (y_{1}) + \pi \leq 0 \\ & Y = [0, 5]^{5} \end{aligned} ``` @@ -29,10 +29,10 @@ Interval analysis shows that the objective value is bounded by the interval ``F` ```math \begin{aligned} -t^{*} = & \min_{\mathbf y \in Y, t \in T} t\\ -{\rm s.t.} \;\; & (24) - (27)\\ -& f(\mathbf y) - t \leq 0\\ -& Y = [0,5]^{2}, \;\; T = [-5,0]. +t^{*} = & \min_{\mathbf y \in Y, t \in T} t \\ +{\rm s.t.} \; \; & (24) - (27) \\ +& f(\mathbf y) - t \leq 0 \\ +& Y = [0,5]^{2}, \; \; T = [-5,0]. \end{aligned} ``` diff --git a/docs/src/index.md b/docs/src/index.md index c1946b61..9c67386c 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -11,9 +11,9 @@ A development environment for robust and global optimization in Julia. - Current Position: Alexion Pharmaceuticals - [Robert Gottlieb](https://psor.uconn.edu/person/robert-gottlieb/), Department of Chemical and Biomolecular Engineering, University of Connecticut (UConn) - [Dimitri Alston](https://psor.uconn.edu/person/dimitri-alston/), Department of Chemical and Biomolecular Engineering, University of Connecticut (UConn) -- [Matthew Stuber](https://chemical-biomolecular.engr.uconn.edu/person/matthew-stuber/), Associate Professor, University of Connecticut (UConn) +- [Matthew Stuber](https://chemical-biomolecular.engr.uconn.edu/people/faculty/stuber-matthew/), Associate Professor, University of Connecticut (UConn) -If you would like to contribute, [contact us](https://psorlab.github.io/EAGO.jl/stable/dev/contributing/). +If you would like to contribute, [contact us](@ref "How to Contribute to EAGO"). ## Overview @@ -27,7 +27,7 @@ EAGO is a registered Julia package and it can be installed using the Julia packa pkg> add EAGO ``` -Currently, EAGO is compatible with version 1.12 of JuMP. This allows a replication of some of the internal features shared by EAGO and JuMP's automatic differentiation scheme, e.g., generation of Wengert Tapes, passing evaluators between JuMP and EAGO, etc. +Currently, EAGO is compatible with version 1.12 of [JuMP](https://github.com/jump-dev/JuMP.jl). This allows a replication of some of the internal features shared by EAGO and JuMP's automatic differentiation scheme, e.g., generation of Wengert Tapes, passing evaluators between JuMP and EAGO, etc. ```jldoctest pkg> add JuMP diff --git a/docs/src/mccormick/overview.md b/docs/src/mccormick/overview.md index 18ead566..3f633818 100644 --- a/docs/src/mccormick/overview.md +++ b/docs/src/mccormick/overview.md @@ -1,8 +1,8 @@ # Overview EAGO provides a library of McCormick relaxations in native Julia code. The EAGO optimizer supports relaxing functions using **nonsmooth McCormick relaxations** ([Mitsos2009](https://epubs.siam.org/doi/abs/10.1137/080717341), [Scott2011](https://link.springer.com/article/10.1007/s10898-011-9664-7)), **smooth McCormick relaxations** ([Khan2016](https://link.springer.com/article/10.1007/s10898-016-0440-6), [Khan2018](https://link.springer.com/article/10.1007/s10898-017-0601-2), [Khan2019](https://www.tandfonline.com/doi/abs/10.1080/02331934.2018.1534108)), and **multi-variant McCormick relaxations** ([Tsoukalas2014](https://link.springer.com/article/10.1007/s10898-014-0176-0); a variant of **subgradient-based interval refinement** ([Najman2017](https://link.springer.com/article/10.1007/s10898-016-0470-0))). For functions with arbitrarily differentiable relaxations, the differentiable constant μ can be modified by adjusting a constant value in the package. Additionally, validated and nonvalidated interval bounds are supported via [IntervalArithmetic.jl](https://github.com/JuliaIntervals/IntervalArithmetic.jl) which is reexported. The basic McCormick operator and reverse McCormick operator ([Wechsung2015](https://link.springer.com/article/10.1007/s10898-015-0303-6)) libraries are included in two dependent subpackages which can loaded and used independently: -- [McCormick.jl](https://github.com/PSORLab/McCormick.jl): A library of forward-mode and implicit McCormick operators. -- [ReverseMcCormick.jl](https://github.com/PSORLab/ReverseMcCormick.jl): A reverse-mode McCormick operator library. +- [McCormick.jl](https://github.com/PSORLab/McCormick.jl): A forward McCormick operator library +- [ReverseMcCormick.jl](https://github.com/PSORLab/ReverseMcCormick.jl): A reverse McCormick operator library ## NaN Numerics diff --git a/docs/src/semiinfinite/semiinfinite.md b/docs/src/semiinfinite/semiinfinite.md index 5bcc30fc..50c19f6c 100644 --- a/docs/src/semiinfinite/semiinfinite.md +++ b/docs/src/semiinfinite/semiinfinite.md @@ -8,21 +8,21 @@ Semi-infinite programming remains an active area of research. In general, the so ```math \begin{aligned} -f^{*} = & \min_{\mathbf x \in X} f(\mathbf x)\\ -{\rm s.t.} \;\; & \max_{\mathbf p \in P} g(\mathbf x, \mathbf p) \leq 0\\ -& \mathbf x \in X = \{ x \in \mathbb R : \mathbf x^{\mathbf L} \leq \mathbf x \leq \mathbf x^{\mathbf U} \}\\ -& \mathbf p \in P = \{ p \in \mathbb R : \mathbf p^{\mathbf L} \leq \mathbf p \leq \mathbf p^{\mathbf U} \} +f^{*} = & \min_{\mathbf x \in X} f(\mathbf x) \\ +{\rm s.t.} \; \; & g(\mathbf x, \mathbf p) \leq 0, \; \; \; \; \forall \mathbf p \in P \\ +& \mathbf x \in X = \{ \mathbf x \in \mathbb R^{n_{x}} : \mathbf x^{L} \leq \mathbf x \leq \mathbf x^{U} \} \\ +& P = \{ \mathbf p \in \mathbb R^{n_{p}} : \mathbf p^{L} \leq \mathbf p \leq \mathbf p^{U} \} \end{aligned} ``` -EAGO implements three different algorithms detailed in [[1](#References),[2](#References)] to determine a globally optimal solution to problems of the above form. This is accomplished using the [`sip_solve`](@ref) function which returns the optimal value, the solution, and a boolean feasibility flag. To illustrate the use of this function, a simple example is presented here which solves the problem: +EAGO implements three different algorithms detailed in [[1](#References), [2](#References)] to determine a globally optimal solution to problems of the above form. This is accomplished using the [`sip_solve`](@ref) function which returns the optimal value, the solution, and a boolean feasibility flag. To illustrate the use of this function, a simple example is presented here which solves the problem: ```math \begin{aligned} -f(\mathbf x) & = \frac{1}{3} x_{1}^{2} + x_{2}^{2} + \frac{x_{1}}{2}\\ -g(\mathbf x, p) & = (1 - x_{1}^{2} p^{2})^{2} - x_{1} p^{2} - x_{2}^{2} + x_{2} \leq 0\\ -& \mathbf x \in X = [-1000, 1000]^{2}\\ -& p \in P = [0, 1]\\ +f(\mathbf x) & = \frac{1}{3} x_{1}^{2} + x_{2}^{2} + \frac{x_{1}}{2} \\ +g(\mathbf x, p) & = (1 - x_{1}^{2} p^{2})^{2} - x_{1} p^{2} - x_{2}^{2} + x_{2} \leq 0 \\ +& \mathbf x \in X = [-1000, 1000]^{2} \\ +& p \in P = [0, 1] \end{aligned} ``` @@ -31,18 +31,14 @@ using EAGO, JuMP # Define semi-infinite program f(x) = (1/3)*x[1]^2 + x[2]^2 + x[1]/2 -gSIP(x, p) = (1.0 - (x[1]^2)*(p[1]^2))^2 - x[1]*p[1]^2 - x[2]^2 + x[2] +gSIP(x, p) = (1.0 - x[1]^2*p[1]^2)^2 - x[1]*p[1]^2 - x[2]^2 + x[2] x_l = Float64[-1000.0, -1000.0] x_u = Float64[1000.0, 1000.0] p_l = Float64[0.0] p_u = Float64[1.0] -sip_result = sip_solve(SIPRes(), x_l, x_u, p_l, p_u, f, Any[gSIP], abs_tolerance = 1E-3) - -println("The global minimum of the semi-infinite program is between: $(sip_result.lower_bound) and $(sip_result.upper_bound).") -println("The global minimum is attained at: x = $(sip_result.xsol).") -println("Is the problem feasible? $(sip_result.feasibility).") +sip_result = sip_solve(SIPRes(), x_l, x_u, p_l, p_u, f, Any[gSIP], res_sip_absolute_tolerance = 1E-3); ``` ## Semi-Infinite Solver diff --git a/src/eago_optimizer/types/global_optimizer.jl b/src/eago_optimizer/types/global_optimizer.jl index 83e36830..6cdcbf3f 100644 --- a/src/eago_optimizer/types/global_optimizer.jl +++ b/src/eago_optimizer/types/global_optimizer.jl @@ -48,7 +48,7 @@ $(TYPEDEF) An Enum of possible values for EAGO's termination status. This attribute is used by EAGO to explain why the optimizer stopped executing in the most recent call -to `optimize!`. See also [`MathOptInterface.TerminationStatusCode`](@ref). +to `optimize!`. See also [`MathOptInterface.TerminationStatusCode`](https://jump.dev/MathOptInterface.jl/stable/reference/models/#MathOptInterface.TerminationStatusCode). If no call has been made to `optimize!`, the `GlobalEndState` value is: - `GS_UNSET`: The optimization algorithm has not stated. From 87484ccf19feb3790d6b480381333852bf296159 Mon Sep 17 00:00:00 2001 From: Dimitri Alston Date: Mon, 6 Nov 2023 15:46:39 -0500 Subject: [PATCH 5/7] Add README for JuMP's packages.toml --- docs/src/jump/README.md | 141 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 docs/src/jump/README.md diff --git a/docs/src/jump/README.md b/docs/src/jump/README.md new file mode 100644 index 00000000..e7ffbde5 --- /dev/null +++ b/docs/src/jump/README.md @@ -0,0 +1,141 @@ + + +# EAGO - Easy Advanced Global Optimization + +EAGO is an open-source development environment for **robust and global optimization** in Julia. See the full [README](https://github.com/PSORLab/EAGO.jl/blob/master/README.md) for more information. + +| **PSOR Lab** | **Current Version** | **Build Status** | **Documentation** | +|:------------:|:-------------------:|:----------------:|:-----------------:| +| [![](https://img.shields.io/badge/Developed_by-PSOR_Lab-342674)](https://psor.uconn.edu/) | [![](https://docs.juliahub.com/EAGO/version.svg)](https://juliahub.com/ui/Packages/General/EAGO) | [![Build Status](https://github.com/PSORLab/EAGO.jl/workflows/CI/badge.svg?branch=master)](https://github.com/PSORLab/EAGO.jl/actions?query=workflow%3ACI) [![codecov](https://codecov.io/gh/PSORLab/EAGO.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/PSORLab/EAGO.jl)| [![](https://img.shields.io/badge/docs-latest-blue.svg)](https://PSORLab.github.io/EAGO.jl/dev) | + +EAGO is a deterministic global optimizer designed to address a wide variety of optimization problems, emphasizing nonlinear programs (NLPs), by propagating McCormick relaxations along the factorable structure of each expression in the NLP. Most operators supported by modern automatic differentiation (AD) packages are supported by EAGO and a number utilities for sanitizing native Julia code and generating relaxations on a wide variety of user-defined functions have been included. Currently, EAGO supports problems that have a priori variable bounds defined and have differentiable constraints. That is, problems should be specified in the generic form below: + +$$ +\begin{align*} +f^{\*} = & \min_{\mathbf y \in Y \subset \mathbb R^{n_{y}}} f(\mathbf y) \\ +{\rm s.t.} \\;\\; & \mathbf h(\mathbf y) = \mathbf 0 \\ +& \mathbf g(\mathbf y) \leq \mathbf 0 \\ +& Y = [\mathbf y^{\mathbf L}, \mathbf y^{\mathbf U}] \in \mathbb{IR}^{n} \\ +& \qquad \mathbf y^{\mathbf L}, \mathbf y^{\mathbf U} \in \mathbb R^{n} +\end{align*} +$$ + +For each nonlinear term, EAGO makes use of factorable representations to construct bounds and relaxations. In the case of $f(x) = x (x - 5) \sin(x)$, a list is generated and rules for constructing McCormick relaxations are used to formulate relaxations in the original decision space, $X$ [[1](#references)]: + +- $v_{1} = x$ +- $v_{2} = v_{1} - 5$ +- $v_{3} = \sin(v_{1})$ +- $v_{4} = v_{1} v_{2}$ +- $v_{5} = v_{4} v_{3}$ +- $f(x) = v_{5}$ + +

+ + +Either these original relaxations, differentiable McCormick relaxations [[2](#references)], or affine relaxations thereof can be used to construct relaxations of optimization problems useful in branch and bound routines for global optimization. Utilities are included to combine these with algorithms for relaxing implicit functions [[3](#references)] and forward-reverse propagation of McCormick arithmetic [[4](#references)]. + +## License + +EAGO is licensed under the [MIT License](https://github.com/PSORLab/EAGO.jl/blob/master/LICENSE.md). + +## Installation + +EAGO is a registered Julia package and it can be installed using the Julia package manager: + +```julia +import Pkg +Pkg.add("EAGO") +``` + +## Use with JuMP + +EAGO makes use of JuMP to improve the user's experience in setting up optimization models. Consider the "process" problem instance from [[5](#references)]: + +$$ +\begin{align*} +& \max_{\mathbf x \in X} 0.063 x_{4} x_{7} - 5.04 x_{1} - 0.035 x_{2} - 10 x_{3} - 3.36 x_{2} \\ +{\rm s.t.} \\;\\; & x_{1} (1.12 + 0.13167 x_{8} - 0.00667 x_{8}^{2}) + x_{4} = 0 \\ +& -0.001 x_{4} x_{9} x_{6} / (98 - x_{6}) + x_{3} = 0 \\ +& -(1.098 x_{8} - 0.038 x_{8}^{2}) - 0.325 x_{6} + x_{7} = 0 \\ +& -(x_{2} + x_{5}) / x_{1} + x_{8} = 0 \\ +& -x_{1} + 1.22 x_{4} - x_{5} = 0 \\ +& x_{9} + 0.222 x_{10} - 35.82 = 0 \\ +& -3.0 x_{7} + x_{10} + 133.0 = 0 \\ +& X = [10, 2000] \times [0, 16000] \times [0, 120] \times [0, 5000] \\ +& \qquad \times [0, 2000] \times [85, 93] \times [90,9 5] \times [3, 12] \times [1.2, 4] \times [145, 162] +\end{align*} +$$ + +This model can be formulated in Julia as: + +```julia +using JuMP, EAGO + +# Build model using EAGO's optimizer +m = Model(EAGO.Optimizer) + +# Define bounded variables +xL = [10.0; 0.0; 0.0; 0.0; 0.0; 85.0; 90.0; 3.0; 1.2; 145.0] +xU = [2000.0; 16000.0; 120.0; 5000.0; 2000.0; 93.0; 95.0; 12.0; 4.0; 162.0] +@variable(m, xL[i] <= x[i=1:10] <= xU[i]) + +# Define nonlinear constraints +@NLconstraint(m, e1, -x[1]*(1.12 + 0.13167*x[8] - 0.00667*(x[8])^2) + x[4] == 0.0) +@NLconstraint(m, e3, -0.001*x[4]*x[9]*x[6]/(98.0 - x[6]) + x[3] == 0.0) +@NLconstraint(m, e4, -(1.098*x[8] - 0.038*(x[8])^2) - 0.325*x[6] + x[7] == 57.425) +@NLconstraint(m, e5, -(x[2] + x[5])/x[1] + x[8] == 0.0) + +# Define linear constraints +@constraint(m, e2, -x[1] + 1.22*x[4] - x[5] == 0.0) +@constraint(m, e6, x[9] + 0.222*x[10] == 35.82) +@constraint(m, e7, -3.0*x[7] + x[10] == -133.0) + +# Define nonlinear objective +@NLobjective(m, Max, 0.063*x[4]*x[7] - 5.04*x[1] - 0.035*x[2] - 10*x[3] - 3.36*x[5]) + +# Solve the optimization problem +JuMP.optimize!(m) +``` + +## Documentation + +EAGO has numerous features: a solver accessible from JuMP/MathOptInterface (MOI), domain reduction routines, McCormick relaxations, and specialized nonconvex semi-infinite program solvers. A full description of all features can be found on the [documentation website](https://psorlab.github.io/EAGO.jl/dev/). A series of example have been provided in the documentation and in the form of Jupyter Notebooks in the separate [EAGO-notebooks](https://github.com/PSORLab/EAGO-notebooks) repository. + +## A Cautionary Note on Global Optimization + +As a global optimization platform, EAGO's solvers can be used to find solutions of general nonconvex problems with a guaranteed certificate of optimality. However, global solvers suffer from the curse of dimensionality and therefore their performance is outstripped by convex/local solvers. For users interested in large-scale applications, be warned that problems generally larger than a few variables may prove challenging for certain types of global optimization problems. + +## Citing EAGO + +Please cite the following paper when using EAGO. In plain text form this is: + +``` +Wilhelm, M.E. and Stuber, M.D. EAGO.jl: easy advanced global optimization in Julia. +Optimization Methods and Software. 37(2): 425-450 (2022). DOI: 10.1080/10556788.2020.1786566 +``` + +As a BibTeX entry: + +```bibtex +@article{doi:10.1080/10556788.2020.1786566, +author = {Wilhelm, M.E. and Stuber, M.D.}, +title = {EAGO.jl: easy advanced global optimization in Julia}, +journal = {Optimization Methods and Software}, +volume = {37}, +number = {2}, +pages = {425-450}, +year = {2022}, +publisher = {Taylor & Francis}, +doi = {10.1080/10556788.2020.1786566}, +URL = {https://doi.org/10.1080/10556788.2020.1786566}, +eprint = {https://doi.org/10.1080/10556788.2020.1786566} +} +``` + +## References + +1. Mitsos, A., Chachuat, B., and Barton, P.I. **McCormick-based relaxations of algorithms.** *SIAM Journal on Optimization*. 20(2): 573–601 (2009). +2. Khan, K.A., Watson, H.A.J., and Barton, P.I. **Differentiable McCormick relaxations.** *Journal of Global Optimization*. 67(4): 687-729 (2017). +3. Stuber, M.D., Scott, J.K., and Barton, P.I.: **Convex and concave relaxations of implicit functions.** *Optimization Methods and Software* 30(3): 424–460 (2015). +4. Wechsung, A., Scott, J.K., Watson, H.A.J., and Barton, P.I. **Reverse propagation of McCormick relaxations.** *Journal of Global Optimization* 63(1): 1-36 (2015). +5. Bracken, J., and McCormick, G.P. *Selected Applications of Nonlinear Programming.* John Wiley and Sons, New York (1968). \ No newline at end of file From da4bc9b7e015637ec2ecc3c16e2d1d22aef12965 Mon Sep 17 00:00:00 2001 From: Dimitri Alston Date: Mon, 6 Nov 2023 16:46:13 -0500 Subject: [PATCH 6/7] Update citation.bib --- citation.bib | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/citation.bib b/citation.bib index 24275398..c33e004d 100644 --- a/citation.bib +++ b/citation.bib @@ -1,12 +1,5 @@ - - - - - - - @article{doi:10.1080/10556788.2020.1786566, -author = {M. E. Wilhelm and M. D. Stuber}, +author = {Wilhelm, M.E. and Stuber, M.D.}, title = {EAGO.jl: easy advanced global optimization in Julia}, journal = {Optimization Methods and Software}, volume = {37}, @@ -15,22 +8,6 @@ @article{doi:10.1080/10556788.2020.1786566 year = {2022}, publisher = {Taylor & Francis}, doi = {10.1080/10556788.2020.1786566}, - -URL = { - - https://doi.org/10.1080/10556788.2020.1786566 - - - -}, -eprint = { - - https://doi.org/10.1080/10556788.2020.1786566 - - - -} - -} - - +URL = {https://doi.org/10.1080/10556788.2020.1786566}, +eprint = {https://doi.org/10.1080/10556788.2020.1786566} +} \ No newline at end of file From 213d32c6bc4690b5cd197f229549fbe95a5951be Mon Sep 17 00:00:00 2001 From: Dimitri Alston Date: Mon, 6 Nov 2023 16:46:51 -0500 Subject: [PATCH 7/7] Fix MOI.TimeLimitSec() test --- src/eago_optimizer/moi_wrapper.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eago_optimizer/moi_wrapper.jl b/src/eago_optimizer/moi_wrapper.jl index 8ddc1ed1..1b6301fd 100644 --- a/src/eago_optimizer/moi_wrapper.jl +++ b/src/eago_optimizer/moi_wrapper.jl @@ -192,7 +192,7 @@ MOI.get(m::Optimizer, ::MOI.TerminationStatus) = m._termination_status_code MOI.get(m::Optimizer, ::MOI.SolveTimeSec) = m._run_time MOI.get(m::Optimizer, ::MOI.NodeCount) = m._node_count MOI.get(m::Optimizer, ::MOI.ResultCount) = (m._result_status_code === MOI.FEASIBLE_POINT) ? 1 : 0 -MOI.get(m::Optimizer, ::MOI.TimeLimitSec) = m._parameters.time_limit +MOI.get(m::Optimizer, ::MOI.TimeLimitSec) = isinf(m._parameters.time_limit) ? nothing : m._parameters.time_limit MOI.get(m::Optimizer, ::MOI.Silent) = m._parameters.verbosity == 0 MOI.get(m::Optimizer, ::MOI.ListOfVariableIndices) = [VI(i) for i = 1:m._input_problem._variable_count]