Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ v0.9.0 (May 2?, 2019)
* The `Utilities.constant` function was renamed to `Utilities.constant_vector`
(#740).
* Implement optimizer attributes for CachingOptimizer (#745).
* Rename `Utilities.add_scalar_constraint` to
`Utilities.normalize_and_add_constraint` (#801).
* `operate` with `vcat`, `SingleVariable` and `VectorOfVariables` now returns
a `VectorOfVariables` (#616).
* Fix a type piracy of `operate` (#784).
Expand Down
7 changes: 5 additions & 2 deletions docs/src/apireference.md
Original file line number Diff line number Diff line change
Expand Up @@ -677,11 +677,14 @@ Utilities.operate!
Utilities.vectorize
```

## Set utilities
## Constraint utilities

The following utilities are available for sets:
The following utilities are available for moving the function constant to the
set for scalar constraints:
```@docs
Utilities.shift_constant
Utilities.normalize_and_add_constraint
Utilities.normalize_constant
```

## Benchmarks
Expand Down
4 changes: 2 additions & 2 deletions src/Bridges/Constraint/det.jl
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ Constrains ``t \\le l_1 + \\cdots + l_n`` where `n` is the length of `l` and ret
function subsum(model, t::MOI.ScalarAffineFunction, l::Vector{MOI.VariableIndex}, ::Type{T}) where T
n = length(l)
f = MOIU.operate!(-, T, t, MOIU.operate(sum, T, l))
return MOIU.add_scalar_constraint(model, f, MOI.LessThan(zero(T)),
allow_modify_function=true)
return MOIU.normalize_and_add_constraint(model, f, MOI.LessThan(zero(T)),
allow_modify_function=true)
end

# Attributes, Bridge acting as a model
Expand Down
2 changes: 1 addition & 1 deletion src/Bridges/Constraint/geomean.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function bridge_constraint(::Type{GeoMeanBridge{T, F, G}}, model,

t = f_scalars[1]
# With sqrt(2)^l*t - xl1, we should scale both the ConstraintPrimal and ConstraintDual
tubc = MOIU.add_scalar_constraint(
tubc = MOIU.normalize_and_add_constraint(
model, MOIU.operate!(+, T, t, -sN * xl1), MOI.LessThan(zero(T)),
allow_modify_function=true)

Expand Down
2 changes: 1 addition & 1 deletion src/Bridges/Constraint/scalarize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function bridge_constraint(::Type{ScalarizeBridge{T, F, S}},
new_f = MOIU.scalarize(f, true)
constraints = Vector{CI{F, S}}(undef, dimension)
for i in 1:dimension
constraints[i] = MOIU.add_scalar_constraint(model, new_f[i], S(-constants[i]))
constraints[i] = MOIU.normalize_and_add_constraint(model, new_f[i], S(-constants[i]))
end
return ScalarizeBridge{T, F, S}(constraints, constants)
end
Expand Down
5 changes: 2 additions & 3 deletions src/Bridges/Constraint/square.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,8 @@ function bridge_constraint(::Type{SquareBridge{T, F, G, TT, ST}},
" coefficients is smaller than 1e-8 but larger than" *
" 1e-10."
end
push!(sym, (i, j) => MOIU.add_scalar_constraint(model, diff,
MOI.EqualTo(zero(T)),
allow_modify_function=true))
push!(sym, (i, j) => MOIU.normalize_and_add_constraint(
model, diff, MOI.EqualTo(zero(T)), allow_modify_function=true))
end
end
k += dim - j
Expand Down
49 changes: 33 additions & 16 deletions src/Utilities/constraints.jl
Original file line number Diff line number Diff line change
@@ -1,29 +1,46 @@
"""
add_scalar_constraint(model::MOI.ModelLike,
func::MOI.AbstractScalarFunction,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool=false)
normalize_and_add_constraint(model::MOI.ModelLike,
func::MOI.AbstractScalarFunction,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool=false)

Adds the scalar constraint obtained by moving the constant term in `func` to
the set in `model`. If `allow_modify_function` is `true` then the function
`func`, can be modified.
`func` can be modified.
"""
function add_scalar_constraint end
function normalize_and_add_constraint end

function add_scalar_constraint(model::MOI.ModelLike, func::MOI.SingleVariable,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool=false)
return MOI.add_constraint(model, func, set)
function normalize_and_add_constraint(model::MOI.ModelLike,
func::MOI.AbstractScalarFunction,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool=false) where T
return MOI.add_constraint(
model, normalize_constant(
func, set; allow_modify_function=allow_modify_function)...)
end
function add_scalar_constraint(model::MOI.ModelLike,
func::Union{MOI.ScalarAffineFunction{T},
MOI.ScalarQuadraticFunction{T}},
set::MOI.AbstractScalarSet;
allow_modify_function::Bool=false) where T

"""
normalize_constant(func::MOI.AbstractScalarFunction,
set::MOI.AbstractScalarSet;
allow_modify_function::Bool=false)

Return the `func`-in-`set` constraint in normalized form. That is, if `func` is
[`MOI.ScalarQuadraticFunction`](@ref) or
[`MOI.ScalarAffineFunction`](@ref), the
constant is moved to the set. If `allow_modify_function` is `true` then the
function `func` can be modified.
"""
function normalize_constant(func::MOI.AbstractFunction, set::MOI.AbstractSet;
allow_modify_function::Bool=false)
return func, set
end
function normalize_constant(
func::Union{MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}},
set::MOI.AbstractScalarSet; allow_modify_function::Bool=false) where T
set = shift_constant(set, -func.constant)
if !allow_modify_function
func = copy(func)
end
func.constant = zero(T)
return MOI.add_constraint(model, func, set)
return func, set
end
2 changes: 1 addition & 1 deletion src/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ function Base.showerror(io::IO,
err::ScalarFunctionConstantNotZero{T, F, S}) where {T, F, S}
print(io, "In `$F`-in-`$S` constraint: Constant $(err.constant) of the ",
"function is not zero. The function constant should be moved to the ",
"set. You can use `MOI.Utilities.add_scalar_constraint` which does ",
"set. You can use `MOI.Utilities.normalize_and_add_constraint` which does ",
"this automatically.")
end

Expand Down
10 changes: 5 additions & 5 deletions test/Utilities/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ const MOI = MathOptInterface
x = MOI.add_variable(model)
@testset "SingleVariable" begin
f = MOI.SingleVariable(x)
ci = MOIU.add_scalar_constraint(model, f, MOI.EqualTo(1.0),
allow_modify_function = false)
ci = MOIU.normalize_and_add_constraint(model, f, MOI.EqualTo(1.0),
allow_modify_function = false)
@test MOI.get(model, MOI.ConstraintFunction(), ci) == f
@test MOI.get(model, MOI.ConstraintSet(), ci) == MOI.EqualTo(1.0)
end
@testset "ScalarAffineFunction" begin
f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 2.0)
g = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0)
ci = MOIU.add_scalar_constraint(model, f, MOI.EqualTo(3.0))
ci = MOIU.normalize_and_add_constraint(model, f, MOI.EqualTo(3.0))
@test f.constant == 2.0
@test MOI.get(model, MOI.ConstraintFunction(), ci) ≈ g
@test MOI.get(model, MOI.ConstraintSet(), ci) == MOI.EqualTo(1.0)
ci = MOIU.add_scalar_constraint(model, f, MOI.Interval(-1.0, 1.0),
allow_modify_function = true)
ci = MOIU.normalize_and_add_constraint(model, f, MOI.Interval(-1.0, 1.0),
allow_modify_function = true)
@test f.constant == 0.0
@test MOI.get(model, MOI.ConstraintFunction(), ci) ≈ g
@test MOI.get(model, MOI.ConstraintSet(), ci) == MOI.Interval(-3.0,
Expand Down