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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ jobs:
# Since MOI doesn't have binary dependencies, only test on a subset of
# possible platforms.
include:
- version: 'nightly'
os: ubuntu-latest
arch: x64
- version: '1'
os: ubuntu-latest
arch: x64
Expand Down
31 changes: 23 additions & 8 deletions src/FileFormats/LP/LP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ import ..FileFormats
import MathOptInterface
const MOI = MathOptInterface

# Julia 1.6 removes Grisu from Base. Previously, we went
# print_shortest(io, x) = Base.Grisu.print_shortest(io, x)
# To avoid adding Grisu as a dependency, use the following printing heuristic.
# TODO(odow): consider printing 1.0 as 1.0 instead of 1, i.e., without the
# rounding branch.
function print_shortest(io::IO, x::Real)
x_int = round(Int, x)
if isapprox(x, x_int)
print(io, x_int)
else
print(io, x)
end
return
end

MOI.Utilities.@model(Model,
(MOI.ZeroOne, MOI.Integer),
(MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval),
Expand Down Expand Up @@ -86,17 +101,17 @@ function write_function(
)
is_first_item = true
if !(func.constant ≈ 0.0)
Base.Grisu.print_shortest(io, func.constant)
print_shortest(io, func.constant)
is_first_item = false
end
for term in func.terms
if !(term.coefficient ≈ 0.0)
if is_first_item
Base.Grisu.print_shortest(io, term.coefficient)
print_shortest(io, term.coefficient)
is_first_item = false
else
print(io, term.coefficient < 0 ? " - " : " + ")
Base.Grisu.print_shortest(io, abs(term.coefficient))
print_shortest(io, abs(term.coefficient))
end

print(io, " ", variable_names[term.variable_index])
Expand All @@ -107,34 +122,34 @@ end

function write_constraint_suffix(io::IO, set::MOI.LessThan)
print(io, " <= ", )
Base.Grisu.print_shortest(io, set.upper)
print_shortest(io, set.upper)
println(io)
return
end

function write_constraint_suffix(io::IO, set::MOI.GreaterThan)
print(io, " >= ", )
Base.Grisu.print_shortest(io, set.lower)
print_shortest(io, set.lower)
println(io)
return
end

function write_constraint_suffix(io::IO, set::MOI.EqualTo)
print(io, " = ", )
Base.Grisu.print_shortest(io, set.value)
print_shortest(io, set.value)
println(io)
return
end

function write_constraint_suffix(io::IO, set::MOI.Interval)
print(io, " <= ", )
Base.Grisu.print_shortest(io, set.upper)
print_shortest(io, set.upper)
println(io)
return
end

function write_constraint_prefix(io::IO, set::MOI.Interval)
Base.Grisu.print_shortest(io, set.lower)
print_shortest(io, set.lower)
print(io, " <= ")
return
end
Expand Down
29 changes: 22 additions & 7 deletions src/FileFormats/MPS/MPS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ import ..FileFormats
import MathOptInterface
const MOI = MathOptInterface

# Julia 1.6 removes Grisu from Base. Previously, we went
# print_shortest(io, x) = Base.Grisu.print_shortest(io, x)
# To avoid adding Grisu as a dependency, use the following printing heuristic.
# TODO(odow): consider printing 1.0 as 1.0 instead of 1, i.e., without the
# rounding branch.
function print_shortest(io::IO, x::Real)
x_int = round(Int, x)
if isapprox(x, x_int)
print(io, x_int)
else
print(io, x)
end
return
end

MOI.Utilities.@model(Model,
(MOI.ZeroOne, MOI.Integer),
(MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval),
Expand Down Expand Up @@ -315,7 +330,7 @@ function write_columns(io::IO, model::Model, ordered_names, names)
Card(
f2 = variable,
f3 = constraint,
f4 = sprint(Base.Grisu.print_shortest, coefficient),
f4 = sprint(print_shortest, coefficient),
)
)
end
Expand Down Expand Up @@ -344,7 +359,7 @@ function _write_rhs(io, model, S, sense_char)
Card(
f2 = "rhs",
f3 = row_name,
f4 = sprint(Base.Grisu.print_shortest, value(set)),
f4 = sprint(print_shortest, value(set)),
)
)
end
Expand Down Expand Up @@ -390,7 +405,7 @@ function write_ranges(io::IO, model::Model)
Card(
f2 = "rhs",
f3 = row_name,
f4 = sprint(Base.Grisu.print_shortest, set.upper - set.lower),
f4 = sprint(print_shortest, set.upper - set.lower),
)
)
end
Expand Down Expand Up @@ -423,7 +438,7 @@ function write_single_bound(io::IO, var_name::String, lower, upper)
f1 = "FX",
f2 = "bounds",
f3 = var_name,
f4 = sprint(Base.Grisu.print_shortest, lower),
f4 = sprint(print_shortest, lower),
)
)
elseif lower == -Inf && upper == Inf
Expand Down Expand Up @@ -452,7 +467,7 @@ function write_single_bound(io::IO, var_name::String, lower, upper)
f1 = "LO",
f2 = "bounds",
f3 = var_name,
f4 = sprint(Base.Grisu.print_shortest, lower),
f4 = sprint(print_shortest, lower),
)
)
end
Expand All @@ -472,7 +487,7 @@ function write_single_bound(io::IO, var_name::String, lower, upper)
f1 = "UP",
f2 = "bounds",
f3 = var_name,
f4 = sprint(Base.Grisu.print_shortest, upper),
f4 = sprint(print_shortest, upper),
)
)
end
Expand Down Expand Up @@ -569,7 +584,7 @@ function write_sos_constraint(io::IO, model::Model, index, names)
io,
Card(
f2 = names[variable],
f3 = sprint(Base.Grisu.print_shortest, weight),
f3 = sprint(print_shortest, weight),
)
)
end
Expand Down
9 changes: 7 additions & 2 deletions src/Utilities/Utilities.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Utilities

using LinearAlgebra # For dot
using OrderedCollections # for OrderedDict in UniversalFallback
using OrderedCollections # for OrderedDict in UniversalFallback

import MutableArithmetics
const MA = MutableArithmetics
Expand All @@ -22,13 +22,18 @@ const VI = MOI.VariableIndex
const CI{F,S} = MOI.ConstraintIndex{F,S}

function print_with_acronym(io::IO, s::AbstractString)
print(io, replace_acronym(s))
end

function replace_acronym(s::AbstractString)
s = replace(s, "MathOptInterface.Utilities" => "MOIU")
s = replace(s, "MathOptInterface.Bridges" => "MOIB")
s = replace(s, "MathOptInterface.Test" => "MOIT")
s = replace(s, "MathOptInterface" => "MOI")
print(io, s)
return s
end


"""
_reverse_dict(src::AbstractDict)

Expand Down
1 change: 1 addition & 0 deletions src/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ output_dimension(::AbstractScalarFunction) = 1

Base.broadcastable(f::AbstractScalarFunction) = Ref(f)
Base.ndims(::Type{<:AbstractScalarFunction}) = 0
Base.ndims(::AbstractScalarFunction) = 0

"""
AbstractVectorFunction
Expand Down
4 changes: 2 additions & 2 deletions test/Bridges/Constraint/functionize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ config_with_basis = MOIT.TestConfig(basis = true)
end

attr = MOIT.UnknownConstraintAttribute()
err = ArgumentError("Bridge of type `MathOptInterface.Bridges.Constraint.ScalarFunctionizeBridge{Float64,MathOptInterface.GreaterThan{Float64}}` does not support setting the attribute `$attr` because `MOIB.Constraint.invariant_under_function_conversion($attr)` returns `false`.")
err = ArgumentError("Bridge of type `$(MathOptInterface.Bridges.Constraint.ScalarFunctionizeBridge{Float64,MathOptInterface.GreaterThan{Float64}})` does not support setting the attribute `$attr` because `MOIB.Constraint.invariant_under_function_conversion($attr)` returns `false`.")
@test_throws err MOI.set(bridged_mock, attr, ci, 1.0)
err = ArgumentError("Bridge of type `MathOptInterface.Bridges.Constraint.ScalarFunctionizeBridge{Float64,MathOptInterface.GreaterThan{Float64}}` does not support accessing the attribute `$attr` because `MOIB.Constraint.invariant_under_function_conversion($attr)` returns `false`.")
err = ArgumentError("Bridge of type `$(MathOptInterface.Bridges.Constraint.ScalarFunctionizeBridge{Float64,MathOptInterface.GreaterThan{Float64}})` does not support accessing the attribute `$attr` because `MOIB.Constraint.invariant_under_function_conversion($attr)` returns `false`.")
@test_throws err MOI.get(bridged_mock, attr, ci)

@testset "delete" begin
Expand Down
2 changes: 1 addition & 1 deletion test/Bridges/Objective/slack.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ end
end

err = ArgumentError(
"Objective bridge of type `MathOptInterface.Bridges.Objective.SlackBridge{Float64,MathOptInterface.ScalarQuadraticFunction{Float64},MathOptInterface.ScalarQuadraticFunction{Float64}}`" *
"Objective bridge of type `$(MathOptInterface.Bridges.Objective.SlackBridge{Float64,MathOptInterface.ScalarQuadraticFunction{Float64},MathOptInterface.ScalarQuadraticFunction{Float64}})`" *
" does not support modifying the objective sense. As a workaround, set" *
" the sense to `MOI.FEASIBILITY_SENSE` to clear the objective function" *
" and bridges."
Expand Down
2 changes: 1 addition & 1 deletion test/Bridges/Variable/vectorize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ end

@testset "get `UnknownVariableAttribute``" begin
err = ArgumentError(
"Variable bridge of type `MathOptInterface.Bridges.Variable.VectorizeBridge{Float64,MathOptInterface.Nonpositives}`" *
"Variable bridge of type `$(MathOptInterface.Bridges.Variable.VectorizeBridge{Float64,MathOptInterface.Nonpositives})`" *
" does not support accessing the attribute `MathOptInterface.Test.UnknownVariableAttribute()`."
)
@test_throws err MOI.get(bridged_mock, MOIT.UnknownVariableAttribute(), y)
Expand Down
10 changes: 5 additions & 5 deletions test/Bridges/bridge_optimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ bridged_mock = MOIB.Constraint.LessToGreater{Float64}(MOIB.Constraint.SplitInter
@testset "Unsupported constraint attribute" begin
attr = MOIT.UnknownConstraintAttribute()
err = ArgumentError(
"Bridge of type `$MOI.Bridges.Constraint.SplitIntervalBridge{Float64,$MOI.SingleVariable,$MOI.Interval{Float64},$MOI.GreaterThan{Float64},$MOI.LessThan{Float64}}` " *
"Bridge of type `$(MOI.Bridges.Constraint.SplitIntervalBridge{Float64,MOI.SingleVariable,MOI.Interval{Float64},MOI.GreaterThan{Float64},MOI.LessThan{Float64}})` " *
"does not support accessing the attribute `$attr`.")
x = MOI.add_variable(bridged_mock)
ci = MOI.add_constraint(bridged_mock, MOI.SingleVariable(x),
Expand Down Expand Up @@ -269,10 +269,10 @@ end
end

@testset "Show" begin
@test sprint(show, bridged_mock) == raw"""
MOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.LessToGreaterBridge{Float64,F,G} where G<:MOI.AbstractScalarFunction where F<:MOI.AbstractScalarFunction,MOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.SplitIntervalBridge{Float64,F,S,LS,US} where US<:MOI.AbstractSet where LS<:MOI.AbstractSet where S<:MOI.AbstractSet where F<:MOI.AbstractFunction,MOIU.MockOptimizer{NoIntervalModel{Float64}}}}
@test sprint(show, bridged_mock) == MOI.Utilities.replace_acronym("""
$(MOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.LessToGreaterBridge{Float64,F,G} where G<:MOI.AbstractScalarFunction where F<:MOI.AbstractScalarFunction,MOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.SplitIntervalBridge{Float64,F,S,LS,US} where US<:MOI.AbstractSet where LS<:MOI.AbstractSet where S<:MOI.AbstractSet where F<:MOI.AbstractFunction,MOIU.MockOptimizer{NoIntervalModel{Float64}}}})
with 1 constraint bridge
with inner model MOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.SplitIntervalBridge{Float64,F,S,LS,US} where US<:MOI.AbstractSet where LS<:MOI.AbstractSet where S<:MOI.AbstractSet where F<:MOI.AbstractFunction,MOIU.MockOptimizer{NoIntervalModel{Float64}}}
with inner model $(MOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.SplitIntervalBridge{Float64,F,S,LS,US} where US<:MOI.AbstractSet where LS<:MOI.AbstractSet where S<:MOI.AbstractSet where F<:MOI.AbstractFunction,MOIU.MockOptimizer{NoIntervalModel{Float64}}})
with 0 constraint bridges
with inner model MOIU.MockOptimizer{NoIntervalModel{Float64}}"""
with inner model $(MOIU.MockOptimizer{NoIntervalModel{Float64}})""")
end
Loading