Skip to content

Commit

Permalink
cleanup and add docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
hdavid16 committed May 10, 2022
1 parent 761adbd commit 4124e18
Show file tree
Hide file tree
Showing 9 changed files with 464 additions and 661 deletions.
1 change: 1 addition & 0 deletions src/DisjunctiveProgramming.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export @disjunction, @proposition

include("constraint.jl")
include("logic.jl")
include("bounds.jl")
include("utils.jl")
include("bigm.jl")
include("hull.jl")
Expand Down
62 changes: 23 additions & 39 deletions src/bigm.jl
Original file line number Diff line number Diff line change
@@ -1,56 +1,40 @@
# function big_m_reformulation!(constr, bin_var, i, k, M)
# if ismissing(k)
# ref = constr
# elseif k isa CartesianIndex
# ref = constr[k]
# else
# ref = constr[k...]
# end
# if ismissing(M)
# M = apply_interval_arithmetic(ref)
# # @warn "No M value passed for $ref. M = $M was inferred from the variable bounds."
# elseif !ismissing(k) && !isa(M,Real)
# M = M[k]
# end
# if ref isa NonlinearConstraintRef
# nonlinear_bigM(ref, bin_var, M, i)
# elseif ref isa ConstraintRef
# linear_bigM(ref, bin_var, M, i)
# end
# end
"""
big_m_reformulation!(constr::ConstraintRef, bin_var, M, i, j, k)
Perform Big-M reformulation on a linear or quadratic constraint at index k of constraint j in disjunct i.
big_m_reformulation!(constr::NonlinearConstraintRef, bin_var, M, i, j, k)
Perform Big-M reformulaiton on a nonlinear constraint at index k of constraint j in disjunct i.
big_m_reformulation!(constr::AbstractArray, bin_var, M, i, j, k)
Perform Big-M reformulation on a constraint at index k of constraint j in disjunct i.
"""
function big_m_reformulation!(constr::ConstraintRef, bin_var, M, i, j, k)
M = get_reform_param(M, i, j, k; constr)
linear_bigM(constr, bin_var, M, i)
bin_var_ref = constr.model[bin_var][i]
add_to_function_constant(constr, -M)
set_normalized_coefficient(constr, bin_var_ref , M)
end
function big_m_reformulation!(constr::NonlinearConstraintRef, bin_var, M, i, j, k)
M = get_reform_param(M, i, j, k; constr)
nonlinear_bigM(constr, bin_var, M, i)
end
big_m_reformulation!(constr::AbstractArray, bin_var, M, i, j, k) =
big_m_reformulation(constr[k], bin_var, M, i, j, k)

function linear_bigM(ref, bin_var, M, i)
bin_var_ref = ref.model[bin_var][i]
add_to_function_constant(ref, -M)
set_normalized_coefficient(ref, bin_var_ref , M)
end

function nonlinear_bigM(ref, bin_var, M, i)
#create symbolic variables (using Symbolics.jl)
for var_ref in ref.model[:gdp_variable_refs]
for var_ref in constr.model[:gdp_variable_refs]
var_sym = Symbol(var_ref)
eval(:(Symbolics.@variables($var_sym)[1]))
end
bin_var_sym = Symbol("$bin_var[$i]")
λ = Num(Symbolics.Sym{Float64}(bin_var_sym))

#parse ref
op, lhs, rhs = parse_NLconstraint(ref)
replace_Symvars!(lhs, ref.model) #convert JuMP variables into Symbolic variables
#parse constr
op, lhs, rhs = parse_constraint(constr)
replace_Symvars!(lhs, constr.model) #convert JuMP variables into Symbolic variables
gx = eval(lhs) #convert the LHS of the constraint into a Symbolic expression
gx = gx - M*(1-λ) #add bigM

#update constraint
replace_NLconstraint(ref, gx, op, rhs)
end
replace_constraint(constr, gx, op, rhs)
end
big_m_reformulation!(constr::AbstractArray, bin_var, M, i, j, k) =
big_m_reformulation(constr[k], bin_var, M, i, j, k)
89 changes: 89 additions & 0 deletions src/bounds.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""
apply_interval_arithmetic(constr)
Apply interval arithmetic on a constraint to find the bounds on the constraint.
"""
function apply_interval_arithmetic(constr)
#convert constraints into Expr to replace variables with interval sets and determine bounds
constr_type, constr_func_expr, constr_rhs = parse_constraint(constr)
#create a map of variables to their bounds
interval_map = Dict()
vars = all_variables(constr.model)#constr.model[:gdp_variable_constrs]
obj_dict = object_dictionary(constr.model)
bounds_dict = :variable_bounds_dict in keys(obj_dict) ? obj_dict[:variable_bounds_dict] : Dict() #NOTE: should pass as an keyword argument
for var in vars
LB, UB = get_bounds(var, bounds_dict)
interval_map[string(var)] = LB..UB
end
constr_func_expr = replace_intevals!(constr_func_expr, interval_map)
#get bounds on the entire expression
func_bounds = eval(constr_func_expr)
Mlo = func_bounds.lo - constr_rhs
Mhi = func_bounds.hi - constr_rhs
M = constr_type == :(<=) ? Mhi : Mlo
isinf(M) && error("M parameter for $constr cannot be infered due to lack of variable bounds.")
return M
end

"""
get_bounds(var::VariableRef)
Get bounds on a variable.
get_bounds(var::VariableRef, bounds_dict::Dict)
Get bounds on a variable. Check if a bounds dictionary has ben provided with bounds for that value.
get_bounds(var::AbstractArray, bounds_dict::Dict, LB, UB)
Update lower bound `LB` and upper bound `UB` on a variable container.
get_bounds(var::Array{VariableRef}, bounds_dict::Dict)
Get lower and upper bounds on a variable array.
get_bounds(var::Containers.DenseAxisArray, bounds_dict::Dict)
Get lower and upper bounds on a variable DenseAxisArray.
get_gounds(var::Containers.SparseAxisArray, bounds_dict::Dict)
Get lower and upper bounds on a variable SparseAxisArray.
"""
function get_bounds(var::VariableRef)
LB = has_lower_bound(var) ? lower_bound(var) : (is_binary(var) ? 0 : -Inf)
UB = has_upper_bound(var) ? upper_bound(var) : (is_binary(var) ? 1 : Inf)
return LB, UB
end
function get_bounds(var::VariableRef, bounds_dict::Dict)
if string(var) in keys(bounds_dict)
return bounds_dict[string(var)]
else
return get_bounds(var)
end
end
function get_bounds(var::AbstractArray, bounds_dict::Dict, LB, UB)
#populate UB and LB
for idx in eachindex(var)
LB[idx], UB[idx] = get_bounds(var[idx], bounds_dict)
end
return LB, UB
end
function get_bounds(var::Array{VariableRef}, bounds_dict::Dict)
#initialize
LB, UB = zeros(size(var)), zeros(size(var))
return get_bounds(var, bounds_dict, LB, UB)
end
function get_bounds(var::Containers.DenseAxisArray, bounds_dict::Dict)
#initialize
LB = Containers.DenseAxisArray(zeros(size(var)), axes(var)...)
UB = Containers.DenseAxisArray(zeros(size(var)), axes(var)...)
return get_bounds(var, bounds_dict, LB, UB)
end
function get_gounds(var::Containers.SparseAxisArray, bounds_dict::Dict)
#initialize
idxs = keys(var.data)
LB = Containers.SparseAxisArray(Dict(idx => 0. for idx in idxs))
UB = Containers.SparseAxisArray(Dict(idx => 0. for idx in idxs))
return get_bounds(var, bounds_dict, LB, UB)
end
Loading

2 comments on commit 4124e18

@hdavid16
Copy link
Owner 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/60023

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.2.0 -m "<description of version>" 4124e18003bbf60ccc98be348dc541f8d4c415a3
git push origin v0.2.0

Please sign in to comment.