Skip to content

Commit

Permalink
Merge pull request #116 from DimitriAlston/master
Browse files Browse the repository at this point in the history
EAGO v0.8.1
  • Loading branch information
DimitriAlston committed Jun 15, 2023
2 parents 55dfdfc + a344e7b commit 839e0fb
Show file tree
Hide file tree
Showing 13 changed files with 68 additions and 23 deletions.
13 changes: 10 additions & 3 deletions News.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
- 4/12/2018: Initial release of combined EAGO packages v0.1.1.

## v0.1.2
- 6/20/2018: [EAGO v0.1.2 has been tagged](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.1.2). Significant speed and functionality updates.
- 6/20/2018: [**EAGO v0.1.2 has been tagged**](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.1.2). Significant speed and functionality updates.

## v0.2.0
- 6/14/2019: [EAGO v0.2.0 has been tagged](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.2.0). This update creates a number of breaking changes to the EAGO API. Please review the use cases provided in the documentation to update examples.
- 6/14/2019: [**EAGO v0.2.0 has been tagged**](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.2.0). This update creates a number of breaking changes to the EAGO API. Please review the use cases provided in the documentation to update examples.
- Updated to support Julia 1.0+, MathOptInterface (MOI), and MOI construction of subproblems.
- Additional domain reduction routines available.
- Support for specialized handling of linear and quadratic terms.
Expand Down Expand Up @@ -60,5 +60,12 @@
- Drops appveyor CI and Travis CI in favor of Github Actions.
- 11/18/2020 [**EAGO v0.5.1 has been tagged**](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.5.1)
- Support for Julia ~1 (with limited functionality for Julia 1.0, 1.1).
- 11/18/2020 **EAGO v0.5.2 has been tagged**
- 11/18/2020 [**EAGO v0.5.2 has been tagged**](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.5.2)
- Fix user specified branching variables.

## v0.8.0
- 6/12/2023: [**EAGO v0.8.0 has been tagged**](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.8.0).
- Updated EAGO for compatibility with the nonlinear expression API changes introduced in JuMP v1.2: https://discourse.julialang.org/t/ann-upcoming-refactoring-of-jumps-nonlinear-api/83052
- EAGO now uses the `MOI.Nonlinear` submodule instead of `JuMP._Derivatives`.
- Models, nodes, expressions, constraints, and operators are now compatible with MOI.
- Added logic and comparison operators to `EAGO.OperatorRegistry`.
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "EAGO"
uuid = "bb8be931-2a91-5aca-9f87-79e1cb69959a"
authors = ["Matthew Wilhelm <matthew.wilhelm@uconn.edu>"]
version = "0.8.0"
version = "0.8.1"

[deps]
Cassette = "7057c7e9-c182-5462-911a-8362d720325c"
Expand Down Expand Up @@ -41,7 +41,7 @@ MINLPTests = "0.5.2"
MathOptInterface = "~1"
McCormick = "0.13"
NaNMath = "0.3.5, 1.0"
PrettyTables = "~1"
PrettyTables = "~2"
Reexport = "~0.2, ~1"
Requires = "~1"
SpecialFunctions = "~1, ~2"
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ As a global optimization platform, EAGO's solvers can be used to find solutions
The EAGO package has numerous features: a solver accessible from JuMP/MathOptInterface (MOI), domain reduction routines, McCormick relaxations, and specialized non-convex semi-infinite program solvers. A full description of all EAGO features is available on the [**documentation website**](https://psorlab.github.io/EAGO.jl/dev/). A series of example have been provided in the form of Jupyter notebooks in the separate [**EAGO-notebooks**](https://github.com/PSORLab/EAGO-notebooks) repository.

## Recent News
- 6/12/2023: [EAGO v0.8.0 has been tagged](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.8.0).
- Updated EAGO for compatibility with the nonlinear expression API changes introduced in JuMP v1.2: https://discourse.julialang.org/t/ann-upcoming-refactoring-of-jumps-nonlinear-api/83052
- EAGO now uses the `MOI.Nonlinear` submodule instead of `JuMP._Derivatives`.
- Models, nodes, expressions, constraints, and operators are now compatible with MOI.
- Added logic and comparison operators to `EAGO.OperatorRegistry`.
- 6/15/2023: [**EAGO v0.8.1 has been tagged**](https://github.com/PSORLab/EAGO.jl/releases/tag/v0.8.1).
- Resolved an issue where integer and binary variables would sometimes throw an `MathOptInterface.UpperBoundAlreadySet` error.
- Added the function `unbounded_check!` which warns users if they are missing variable bounds and sets them to +/- 1E10 by default.
- Added an EAGO parameter `unbounded_check` which defaults to `true` and enables `unbounded_check!`.
- Bumped requirement for PrettyTables.jl to v2+ to accomodate the latest version of DataFrames.jl.

For a full list of EAGO release news, click [**here**](https://github.com/PSORLab/EAGO.jl/releases).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ end
MC(x::MCAffPnt{N,T}) where {N,T<:RelaxTag} = x.v
MC(x::MC{N,T}) where {N, T<:RelaxTag} = x

relax_info(s::RelaxAA, n::Int, t::T) where {N,T} = MCAffPnt{n,T}
relax_info(s::RelaxAA, n::Int, t::T) where T = MCAffPnt{n,T}

zero(::Type{MCAffPnt{N,T}}) where {N,T} = MCAffPnt{N,T}(zero(MC{N,T}), zero(AffineEAGO{N}))
zero(x::MCAffPnt{N,T}) where {N,T} = MCAffPnt{N,T}(zero(x.v), zero(x.box))
Expand Down Expand Up @@ -297,7 +297,7 @@ function cut(x::MC{N,T}, z::MCAffPnt{N,T}, v::VariableValues, ϵ::Float64, s::Ve
return x
end

function varset(::Type{MCAffPnt{N,T}}, i, x_cv, x_cc, l, u) where {V,N,T<:RelaxTag}
function varset(::Type{MCAffPnt{N,T}}, i, x_cv, x_cc, l, u) where {N,T<:RelaxTag}
v = seed_gradient(i, Val(N))
v_Intv = Interval{Float64}(l, u)
v_mc = MC{N,T}(x_cv, x_cc, v_Intv, v, v, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,5 +284,5 @@ function display_table!(g::DAT, b::RelaxCache{V,N,T}) where {V,N,T<:RelaxTag}
val = [b._is_num[i] ? b._num[i] : b._set[i] for i in 1:nc]
exr = [display_expr(g, i) for i in 1:nc]
data = hcat(exr, b._is_num, val)
show(pretty_table(data, header = ["Expr", "Is Num", "Val"]; show_row_number = true))
pretty_table(data, header = ["Expr", "Is Num", "Val"]; show_row_number = true)
end
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ xset_ynum(b, x, y) = !is_num(b, x) && is_num(b, y)
xy_num(b, x, y) = is_num(b, x) && is_num(b, y)
xyset(b, x, y) = !(is_num(b, x) || is_num(b, y))

function varset(::Type{MC{N,T}}, i, x_cv, x_cc, l, u) where {V,N,T<:RelaxTag}
function varset(::Type{MC{N,T}}, i, x_cv, x_cc, l, u) where {N,T<:RelaxTag}
v = seed_gradient(i, Val(N))
return MC{N,T}(x_cv, x_cc, Interval{Float64}(l, u), v, v, false)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function expand_set(::Type{MC{N2,T}}, x::MC{N1,T}, fsparse::Vector{Int}, subspar
return MC{N2,T}(x.cv, x.cc, x.Intv, cv_grad, cc_grad, x.cnst)
end

function set_value_post(z::MC{N,T}, v::VariableValues{Float64}, s::Vector{Int}, ϵ::Float64) where {V,N,T<:RelaxTag}
function set_value_post(z::MC{N,T}, v::VariableValues{Float64}, s::Vector{Int}, ϵ::Float64) where {N,T<:RelaxTag}
l = z.cv
u = z.cc
lower_refinement = true
Expand Down
2 changes: 1 addition & 1 deletion src/eago_optimizer/moi_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ MOI.get(m::Optimizer, ::MOI.DualStatus) = MOI.NO_SOLUTION
MOI.get(m::Optimizer, ::MOI.ObjectiveBound) = m._objective_bound
MOI.get(m::Optimizer, ::MOI.NumberOfVariables) = m._input_problem._variable_count
MOI.get(m::Optimizer, ::MOI.SolverName) = "EAGO: Easy Advanced Global Optimization"
MOI.get(m::Optimizer, ::MOI.SolverVersion) = "0.7.1"
MOI.get(m::Optimizer, ::MOI.SolverVersion) = "0.8.1"
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
Expand Down
4 changes: 2 additions & 2 deletions src/eago_optimizer/optimize/nonconvex/display.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#############################################################################
# src/eago_optimizer/display.jl
# Functions used to print information about solution routine to console.
# Printing is done with reference to the input problem is there is any
# Printing is done with reference to the input problem if there is any
# ambiguity.
#############################################################################

Expand Down Expand Up @@ -44,7 +44,7 @@ function print_solution!(m::GlobalOptimizer)
println("LBD = $(MOI.get(m, MOI.ObjectiveBound()))")
println("UBD = $(MOI.get(m, MOI.ObjectiveValue()))")
end
println("Solution is :")
println("Solution is:")
if m._feasible_solution_found
for i = 1:m._input_problem._variable_count
println(" X[$i] = $(m._continuous_solution[i])")
Expand Down
2 changes: 1 addition & 1 deletion src/eago_optimizer/optimize/nonconvex/relax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Default routine for relaxing quadratic constraint `func < 0.0` on node `n`.
Takes affine bounds of convex part at point `x0` and secant line bounds on
concave parts.
"""
function affine_relax_quadratic!(m::GlobalOptimizer, func::SQF, buffer::Dict{Int,Float64}, saf::SAF) where {R,S,Q<:ExtensionType}
function affine_relax_quadratic!(m::GlobalOptimizer, func::SQF, buffer::Dict{Int,Float64}, saf::SAF)

quadratic_constant = func.constant

Expand Down
33 changes: 33 additions & 0 deletions src/eago_optimizer/optimize/nonconvex/stack_management.jl
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,43 @@ fathom!(m::GlobalOptimizer{R,S,Q}) where {R,S,Q<:ExtensionType} = fathom!(_ext(m
"""
$(TYPEDSIGNATURES)
Check the optimization problem for unbounded branching variables, which would interfere
with EAGO's branch-and-bound routine since there are no well-defined branching rules
for cases where the interval bounds contain `-Inf` or `Inf`. If any branching variables
are missing bounds, add the missing bound at +/- 1e10 and warn the user.
"""
function unbounded_check!(m::GlobalOptimizer)
if m._parameters.unbounded_check
unbounded_flag = false
wp = m._working_problem
epigraph_flag = _variable_num(FullVar(), m) != m._input_problem._variable_count
for i = 1:_variable_num(BranchVar(), m) - epigraph_flag #Not including epigraph reformulation variable
if !wp._variable_info[i].has_lower_bound
unbounded_flag = true
wp._variable_info[i] = VariableInfo(wp._variable_info[i], GT(-1e10))
end
if !wp._variable_info[i].has_upper_bound
unbounded_flag = true
wp._variable_info[i] = VariableInfo(wp._variable_info[i], LT(1e10))
end
end
unbounded_flag && @warn("""
At least one branching variable is unbounded. This will interfere with EAGO's global
optimization routine and may cause unexpected results. Bounds have been automatically
generated at +/- 1e10 for all unbounded variables, but tighter user-defined bounds are
highly recommended. To disable this warning and the automatic generation of bounds, use
the option `unbounded_check = false`.""")
end
end

"""
$(TYPEDSIGNATURES)
Prepare the stack for the branch-and-bound routine. By default, create an
initial node with the variable bounds as box constraints and add it to the stack.
"""
function initialize_stack!(t::ExtensionType, m::GlobalOptimizer)
unbounded_check!(m)
d = _working_variable_info.(m, m._branch_to_sol_map)
push!(m._stack, NodeBB(lower_bound.(d), upper_bound.(d), is_integer.(d)))
m._node_count = 1
Expand Down
7 changes: 5 additions & 2 deletions src/eago_optimizer/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,10 @@ function label_branch_variables!(m::GlobalOptimizer)
for i = 1:wp._variable_count
if is_fixed(wp._variable_info[i])
m._branch_variables[i] = false
elseif m._branch_variables[i] || wp._variable_info[i].is_integer
elseif m._branch_variables[i]
push!(m._branch_to_sol_map, i)
elseif wp._variable_info[i].is_integer
m._branch_variables[i] = true
push!(m._branch_to_sol_map, i)
elseif i == wp._variable_count
m._branch_variables[i] = false
Expand Down Expand Up @@ -534,4 +537,4 @@ function parse_classify_problem!(m::GlobalOptimizer)
end

return
end
end
6 changes: 4 additions & 2 deletions src/eago_optimizer/types/global_optimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ Base.@kwdef mutable struct EAGOParameters
cut_safe_b::Float64 = 1E9

"Solve upper problem for every node with depth less than `upper_bounding_depth`,
and otherwise solve upper problems with a probability of (1/2)^(depth-upper_bounding_depth)
and otherwise solve upper problems with a probability of `(1/2)^(depth-upper_bounding_depth)`
(default = 8)"
upper_bounding_depth::Int = 8

Expand All @@ -241,8 +241,10 @@ Base.@kwdef mutable struct EAGOParameters
integer_rel_tol::Float64 = 1E-9

# Other forcing options
"Ignore EAGO's ability to parse problem types and force it to run global optimization"
"Ignore EAGO's ability to parse problem types and force it to run global optimization (default = false)"
force_global_solve::Bool = false
"Check that all branching variables have finite bounds and set them to +/- 1E10 if not (default = true)"
unbounded_check::Bool = true
end
const EAGO_PARAMETERS = fieldnames(EAGOParameters)

Expand Down

2 comments on commit 839e0fb

@DimitriAlston
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/85680

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.8.1 -m "<description of version>" 839e0fb9aafff3a935906164b6e11641f86bbf73
git push origin v0.8.1

Please sign in to comment.