From c1a34490d60f81474fb1c985b33981c3f98e560d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sun, 30 Dec 2018 11:33:37 +0100 Subject: [PATCH 01/11] =?UTF-8?q?=E2=9C=85=20Fix=20JuMPExtension=20print?= =?UTF-8?q?=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nlp.jl | 14 +++ src/print.jl | 100 +++++++++------- test/JuMPExtension.jl | 17 +++ test/print.jl | 258 +++++++++++++++++++++++++----------------- 4 files changed, 243 insertions(+), 146 deletions(-) diff --git a/src/nlp.jl b/src/nlp.jl index 317c5a06fdd..b5bce466c89 100644 --- a/src/nlp.jl +++ b/src/nlp.jl @@ -71,6 +71,20 @@ mutable struct NLPData evaluator end +""" + nlp_objective_function(model::Model) + +Returns the nonlinear objective function or `nothing` if no nonlinear objective +function is set. +""" +function nlp_objective_function(model::Model) + if model.nlp_data isa Nothing + return nothing + else + return model.nlp_data.nlobj + end +end + function create_nlp_block_data(m::Model) @assert m.nlp_data !== nothing bounds = MOI.NLPBoundsPair[] diff --git a/src/print.jl b/src/print.jl index 8ade8564ad4..ae083795457 100644 --- a/src/print.jl +++ b/src/print.jl @@ -143,11 +143,12 @@ end wrap_in_math_mode(str) = "\$\$ $str \$\$" wrap_in_inline_math_mode(str) = "\$ $str \$" +plural(n) = (n==1 ? "" : "s") + #------------------------------------------------------------------------ ## Model #------------------------------------------------------------------------ -function Base.show(io::IO, model::Model) - plural(n) = (n==1 ? "" : "s") +function Base.show(io::IO, model::AbstractModel) println(io, "A JuMP Model") sense = objective_sense(model) if sense == MOI.MAX_SENSE @@ -162,22 +163,25 @@ function Base.show(io::IO, model::Model) println(io, "Variable", plural(num_variables(model)), ": ", num_variables(model)) if sense != MOI.FEASIBILITY_SENSE - if model.nlp_data !== nothing && model.nlp_data.nlobj !== nothing - println(io, "Objective function type: Nonlinear") - else + nlobj = nlp_objective_function(model) + if nlobj isa Nothing println(io, "Objective function type: ", - MOI.get(model, MOI.ObjectiveFunctionType())) + objective_function_type(model)) + else + println(io, "Objective function type: Nonlinear") end end - for (F, S) in MOI.get(model, MOI.ListOfConstraints()) - num_constraints = MOI.get(model, MOI.NumberOfConstraints{F, S}()) - println(io, "`$F`-in-`$S`: $num_constraints constraint", - plural(num_constraints)) - end - if !iszero(num_nl_constraints(model)) - println(io, "Nonlinear: ", num_nl_constraints(model), " constraint", - plural(num_nl_constraints(model))) + show_constraints_summary(io, model) + show_backend_summary(io, model) + names_in_scope = sort(collect(keys(object_dictionary(model)))) + if !isempty(names_in_scope) + println(io) + print(io, "Names registered in the model: ", + join(string.(names_in_scope), ", ")) end +end + +function show_backend_summary(io::IO, model::Model) model_mode = mode(model) println(io, "Model mode: ", model_mode) if model_mode == MANUAL || model_mode == AUTOMATIC @@ -186,21 +190,15 @@ function Base.show(io::IO, model::Model) end # The last print shouldn't have a new line print(io, "Solver name: ", solver_name(model)) - names_in_scope = sort(collect(keys(object_dictionary(model)))) - if !isempty(names_in_scope) - println(io) - print(io, "Names registered in the model: ", - join(string.(names_in_scope), ", ")) - end end -function Base.print(io::IO, model::Model) +function Base.print(io::IO, model::AbstractModel) print(io, model_string(REPLMode, model)) end -function Base.show(io::IO, ::MIME"text/latex", model::Model) +function Base.show(io::IO, ::MIME"text/latex", model::AbstractModel) print(io, wrap_in_math_mode(model_string(IJuliaMode, model))) end -function model_string(print_mode, model::Model) +function model_string(print_mode, model::AbstractModel) ijl = print_mode == IJuliaMode sep = ijl ? " & " : " " eol = ijl ? "\\\\\n" : "\n" @@ -218,30 +216,16 @@ function model_string(print_mode, model::Model) str *= "\\quad" end str *= sep - if model.nlp_data !== nothing && model.nlp_data.nlobj !== nothing - str *= nl_expr_string(model, print_mode, model.nlp_data.nlobj) + nlobj = nlp_objective_function(model) + if nlobj isa Nothing + str *= function_string(print_mode, objective_function(model)) else - str *= function_string(print_mode, - objective_function(model, QuadExpr)) + str *= nl_expr_string(model, print_mode, nlobj) end end str *= eol str *= ijl ? "\\text{Subject to} \\quad" : "Subject to" * eol - for (F, S) in MOI.get(model, MOI.ListOfConstraints()) - for idx in MOI.get(model, MOI.ListOfConstraintIndices{F, S}()) - # FIXME the shape may be incorrect here - shape = S <: MOI.AbstractScalarSet ? ScalarShape() : VectorShape() - cref = ConstraintRef(model, idx, shape) - con = constraint_object(cref) - str *= sep * constraint_string(print_mode, con) * eol - end - end - if model.nlp_data !== nothing - for nl_constraint in model.nlp_data.nlconstr - str *= sep * nl_constraint_string(model, print_mode, nl_constraint) - str *= eol - end - end + str *= constraints_string(print_mode, model, sep, eol) if ijl str = "\\begin{alignat*}{1}" * str * "\\end{alignat*}\n" end @@ -370,6 +354,38 @@ end ## Constraints #------------------------------------------------------------------------ +function show_constraints_summary(io::IO, model::Model) + for (F, S) in MOI.get(model, MOI.ListOfConstraints()) + num_constraints = MOI.get(model, MOI.NumberOfConstraints{F, S}()) + println(io, "`$F`-in-`$S`: $num_constraints constraint", + plural(num_constraints)) + end + if !iszero(num_nl_constraints(model)) + println(io, "Nonlinear: ", num_nl_constraints(model), " constraint", + plural(num_nl_constraints(model))) + end +end + +function constraints_string(print_mode, model::Model, sep, eol) + str = "" + for (F, S) in MOI.get(model, MOI.ListOfConstraints()) + for idx in MOI.get(model, MOI.ListOfConstraintIndices{F, S}()) + # FIXME the shape may be incorrect here + shape = S <: MOI.AbstractScalarSet ? ScalarShape() : VectorShape() + cref = ConstraintRef(model, idx, shape) + con = constraint_object(cref) + str *= sep * constraint_string(print_mode, con) * eol + end + end + if model isa Model && model.nlp_data !== nothing + for nl_constraint in model.nlp_data.nlconstr + str *= sep * nl_constraint_string(model, print_mode, nl_constraint) + str *= eol + end + end + return str +end + ## Notes for extensions # For a `ConstraintRef{ModelType, IndexType}` where `ModelType` is not # `JuMP.Model` or `IndexType` is not `MathOptInterface.ConstraintIndex`, the diff --git a/test/JuMPExtension.jl b/test/JuMPExtension.jl index 0737332c18f..f19cd62207d 100644 --- a/test/JuMPExtension.jl +++ b/test/JuMPExtension.jl @@ -219,6 +219,7 @@ function JuMP.constraint_object(cref::MyConstraintRef) end # Objective +JuMP.nlp_objective_function(::MyModel) = nothing function JuMP.set_objective(m::MyModel, sense::MOI.OptimizationSense, f::JuMP.AbstractJuMPScalar) m.objectivesense = sense @@ -299,4 +300,20 @@ function JuMP.constraint_by_name(model::MyModel, name::String) end end +# Show +function JuMP.show_constraints_summary(io::IO, model::MyModel) + n = length(model.constraints) + print(io, "Constraint", JuMP.plural(n), ": ", n) +end +function JuMP.show_backend_summary(io::IO, model::MyModel) end +function JuMP.constraints_string(print_mode, model::MyModel, sep, eol) + str = "" + # Sort by creation order, i.e. ConstraintIndex value + constraints = sort(collect(model.constraints), by = c -> c.first.value) + for (index, constraint) in constraints + str *= sep * JuMP.constraint_string(print_mode, constraint) * eol + end + return str +end + end diff --git a/test/print.jl b/test/print.jl index a945f6c57c5..2a9bff0fbf9 100644 --- a/test/print.jl +++ b/test/print.jl @@ -202,7 +202,8 @@ end end end -function printing_test(ModelType::Type{<:JuMP.AbstractModel}) +function printing_test(ModelType::Type{<:JuMP.AbstractModel}, + moi_backend::Bool) @testset "VariableRef" begin m = ModelType() @variable(m, 0 <= x <= 2) @@ -266,18 +267,6 @@ function printing_test(ModelType::Type{<:JuMP.AbstractModel}) io_test(IJuliaMode, w[1,3], "symm_{1,3}") end - @testset "SingleVariable constraints" begin - ge = JuMP.math_symbol(REPLMode, :geq) - in_sym = JuMP.math_symbol(REPLMode, :in) - model = ModelType() - @variable(model, x >= 10) - zero_one = @constraint(model, x in MathOptInterface.ZeroOne()) - - io_test(REPLMode, JuMP.LowerBoundRef(x), "x $ge 10.0") - io_test(REPLMode, zero_one, "x binary") - # TODO: Test in IJulia mode - end - @testset "VectorOfVariable constraints" begin ge = JuMP.math_symbol(REPLMode, :geq) in_sym = JuMP.math_symbol(REPLMode, :in) @@ -375,74 +364,107 @@ function printing_test(ModelType::Type{<:JuMP.AbstractModel}) @constraint(model_1, a*b <= 2) @constraint(model_1, [1 - a; u] in SecondOrderCone()) - io_test(REPLMode, model_1, """ - Max a - b + 2 a1 - 10 x - Subject to - x binary - u[1] binary - u[2] binary - u[3] binary - a1 integer - b1 integer - c1 integer - z integer - fi $eq 9.0 - a $ge 1.0 - c $ge -1.0 - a1 $ge 1.0 - c1 $ge -1.0 - b $le 1.0 - c $le 1.0 - b1 $le 1.0 - c1 $le 1.0 - a + b - 10 c - 2 x + c1 $le 1.0 - a*b $le 2.0 - [-a + 1, u[1], u[2], u[3]] $inset MathOptInterface.SecondOrderCone(4) - """, repl=:print) + VariableType = typeof(a) + + if moi_backend + io_test(REPLMode, model_1, """ + Max a - b + 2 a1 - 10 x + Subject to + x binary + u[1] binary + u[2] binary + u[3] binary + a1 integer + b1 integer + c1 integer + z integer + fi $eq 9.0 + a $ge 1.0 + c $ge -1.0 + a1 $ge 1.0 + c1 $ge -1.0 + b $le 1.0 + c $le 1.0 + b1 $le 1.0 + c1 $le 1.0 + a + b - 10 c - 2 x + c1 $le 1.0 + a*b $le 2.0 + [-a + 1, u[1], u[2], u[3]] $inset MathOptInterface.SecondOrderCone(4) + """, repl=:print) + else + # TODO variable constraints + io_test(REPLMode, model_1, """ + Max a - b + 2 a1 - 10 x + Subject to + a + b - 10 c - 2 x + c1 $le 1.0 + a*b $le 2.0 + [-a + 1, u[1], u[2], u[3]] $inset MathOptInterface.SecondOrderCone(4) + """, repl=:print) + end - io_test(REPLMode, model_1, """ - A JuMP Model - Maximization problem with: - Variables: 13 - Objective function type: MathOptInterface.ScalarAffineFunction{Float64} - `MathOptInterface.SingleVariable`-in-`MathOptInterface.ZeroOne`: 4 constraints - `MathOptInterface.SingleVariable`-in-`MathOptInterface.Integer`: 4 constraints - `MathOptInterface.SingleVariable`-in-`MathOptInterface.EqualTo{Float64}`: 1 constraint - `MathOptInterface.SingleVariable`-in-`MathOptInterface.GreaterThan{Float64}`: 4 constraints - `MathOptInterface.SingleVariable`-in-`MathOptInterface.LessThan{Float64}`: 4 constraints - `MathOptInterface.ScalarAffineFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint - `MathOptInterface.ScalarQuadraticFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint - `MathOptInterface.VectorAffineFunction{Float64}`-in-`MathOptInterface.SecondOrderCone`: 1 constraint - Model mode: AUTOMATIC - CachingOptimizer state: NO_OPTIMIZER - Solver name: No optimizer attached. - Names registered in the model: a, a1, b, b1, c, c1, fi, u, x, y, z""", repl=:show) - - io_test(IJuliaMode, model_1, """ - \\begin{alignat*}{1}\\max\\quad & a - b + 2 a1 - 10 x\\\\ - \\text{Subject to} \\quad & x binary\\\\ - & u_{1} binary\\\\ - & u_{2} binary\\\\ - & u_{3} binary\\\\ - & a1 integer\\\\ - & b1 integer\\\\ - & c1 integer\\\\ - & z integer\\\\ - & fi = 9.0\\\\ - & a \\geq 1.0\\\\ - & c \\geq -1.0\\\\ - & a1 \\geq 1.0\\\\ - & c1 \\geq -1.0\\\\ - & b \\leq 1.0\\\\ - & c \\leq 1.0\\\\ - & b1 \\leq 1.0\\\\ - & c1 \\leq 1.0\\\\ - & a + b - 10 c - 2 x + c1 \\leq 1.0\\\\ - & a\\times b \\leq 2.0\\\\ - & [-a + 1, u_{1}, u_{2}, u_{3}] \\in MathOptInterface.SecondOrderCone(4)\\\\ - \\end{alignat*} - """) + if moi_backend + io_test(REPLMode, model_1, """ + A JuMP Model + Maximization problem with: + Variables: 13 + Objective function type: JuMP.GenericAffExpr{Float64,$VariableType} + `MathOptInterface.SingleVariable`-in-`MathOptInterface.ZeroOne`: 4 constraints + `MathOptInterface.SingleVariable`-in-`MathOptInterface.Integer`: 4 constraints + `MathOptInterface.SingleVariable`-in-`MathOptInterface.EqualTo{Float64}`: 1 constraint + `MathOptInterface.SingleVariable`-in-`MathOptInterface.GreaterThan{Float64}`: 4 constraints + `MathOptInterface.SingleVariable`-in-`MathOptInterface.LessThan{Float64}`: 4 constraints + `MathOptInterface.ScalarAffineFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint + `MathOptInterface.ScalarQuadraticFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint + `MathOptInterface.VectorAffineFunction{Float64}`-in-`MathOptInterface.SecondOrderCone`: 1 constraint + Model mode: AUTOMATIC + CachingOptimizer state: NO_OPTIMIZER + Solver name: No optimizer attached. + Names registered in the model: a, a1, b, b1, c, c1, fi, u, x, y, z""", repl=:show) + else + io_test(REPLMode, model_1, """ + A JuMP Model + Maximization problem with: + Variables: 13 + Objective function type: JuMP.GenericAffExpr{Float64,$VariableType} + Constraints: 3 + Names registered in the model: a, a1, b, b1, c, c1, fi, u, x, y, z""", repl=:show) + end + + if moi_backend + io_test(IJuliaMode, model_1, """ + \\begin{alignat*}{1}\\max\\quad & a - b + 2 a1 - 10 x\\\\ + \\text{Subject to} \\quad & x binary\\\\ + & u_{1} binary\\\\ + & u_{2} binary\\\\ + & u_{3} binary\\\\ + & a1 integer\\\\ + & b1 integer\\\\ + & c1 integer\\\\ + & z integer\\\\ + & fi = 9.0\\\\ + & a \\geq 1.0\\\\ + & c \\geq -1.0\\\\ + & a1 \\geq 1.0\\\\ + & c1 \\geq -1.0\\\\ + & b \\leq 1.0\\\\ + & c \\leq 1.0\\\\ + & b1 \\leq 1.0\\\\ + & c1 \\leq 1.0\\\\ + & a + b - 10 c - 2 x + c1 \\leq 1.0\\\\ + & a\\times b \\leq 2.0\\\\ + & [-a + 1, u_{1}, u_{2}, u_{3}] \\in MathOptInterface.SecondOrderCone(4)\\\\ + \\end{alignat*} + """) + else + io_test(IJuliaMode, model_1, """ + \\begin{alignat*}{1}\\max\\quad & a - b + 2 a1 - 10 x\\\\ + \\text{Subject to} \\quad & a + b - 10 c - 2 x + c1 \\leq 1.0\\\\ + & a\\times b \\leq 2.0\\\\ + & [-a + 1, u_{1}, u_{2}, u_{3}] \\in MathOptInterface.SecondOrderCone(4)\\\\ + \\end{alignat*} + """) + end #------------------------------------------------------------------ @@ -451,36 +473,54 @@ function printing_test(ModelType::Type{<:JuMP.AbstractModel}) @variable(model_2, y, Int) @constraint(model_2, x*y <= 1) - io_test(REPLMode, model_2, """ - A JuMP Model - Feasibility problem with: - Variables: 2 - `MathOptInterface.SingleVariable`-in-`MathOptInterface.ZeroOne`: 1 constraint - `MathOptInterface.SingleVariable`-in-`MathOptInterface.Integer`: 1 constraint - `MathOptInterface.ScalarQuadraticFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint - Model mode: AUTOMATIC - CachingOptimizer state: NO_OPTIMIZER - Solver name: No optimizer attached. - Names registered in the model: x, y""", repl=:show) + if moi_backend + io_test(REPLMode, model_2, """ + A JuMP Model + Feasibility problem with: + Variables: 2 + `MathOptInterface.SingleVariable`-in-`MathOptInterface.ZeroOne`: 1 constraint + `MathOptInterface.SingleVariable`-in-`MathOptInterface.Integer`: 1 constraint + `MathOptInterface.ScalarQuadraticFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint + Model mode: AUTOMATIC + CachingOptimizer state: NO_OPTIMIZER + Solver name: No optimizer attached. + Names registered in the model: x, y""", repl=:show) + else + io_test(REPLMode, model_2, """ + A JuMP Model + Feasibility problem with: + Variables: 2 + Constraint: 1 + Names registered in the model: x, y""", repl=:show) + end model_2 = ModelType() @variable(model_2, x) @constraint(model_2, x <= 3) - io_test(REPLMode, model_2, """ - A JuMP Model - Feasibility problem with: - Variable: 1 - `MathOptInterface.ScalarAffineFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint - Model mode: AUTOMATIC - CachingOptimizer state: NO_OPTIMIZER - Solver name: No optimizer attached. - Names registered in the model: x""", repl=:show) + if moi_backend + io_test(REPLMode, model_2, """ + A JuMP Model + Feasibility problem with: + Variable: 1 + `MathOptInterface.ScalarAffineFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint + Model mode: AUTOMATIC + CachingOptimizer state: NO_OPTIMIZER + Solver name: No optimizer attached. + Names registered in the model: x""", repl=:show) + else + io_test(REPLMode, model_2, """ + A JuMP Model + Feasibility problem with: + Variable: 1 + Constraint: 1 + Names registered in the model: x""", repl=:show) + end end end @testset "Printing for JuMP.Model" begin - printing_test(Model) + printing_test(Model, true) @testset "Model with nonlinear terms" begin eq = JuMP.math_symbol(REPLMode, :eq) model = Model() @@ -511,9 +551,19 @@ end \\end{alignat*} """) end + @testset "SingleVariable constraints" begin + ge = JuMP.math_symbol(REPLMode, :geq) + in_sym = JuMP.math_symbol(REPLMode, :in) + model = Model() + @variable(model, x >= 10) + zero_one = @constraint(model, x in MathOptInterface.ZeroOne()) + + io_test(REPLMode, JuMP.LowerBoundRef(x), "x $ge 10.0") + io_test(REPLMode, zero_one, "x binary") + # TODO: Test in IJulia mode + end end -# TODO: These tests are failing. -# @testset "Printing for JuMPExtension.MyModel" begin -# printing_test(JuMPExtension.MyModel) -# end +@testset "Printing for JuMPExtension.MyModel" begin + printing_test(JuMPExtension.MyModel, false) +end From 74282514eb3e245ce19b68c4e882b8f1b36bf4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Tue, 1 Jan 2019 01:49:19 +0100 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=94=A5=20Remove=20useless=20conditi?= =?UTF-8?q?on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/print.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/print.jl b/src/print.jl index ae083795457..49095b4b860 100644 --- a/src/print.jl +++ b/src/print.jl @@ -377,7 +377,7 @@ function constraints_string(print_mode, model::Model, sep, eol) str *= sep * constraint_string(print_mode, con) * eol end end - if model isa Model && model.nlp_data !== nothing + if model.nlp_data !== nothing for nl_constraint in model.nlp_data.nlconstr str *= sep * nl_constraint_string(model, print_mode, nl_constraint) str *= eol From b77b0fdb4911386ffd6f2ebae3ae8e5618148ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Tue, 1 Jan 2019 01:53:27 +0100 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstring=20for=20pr?= =?UTF-8?q?inting=5Ftest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/print.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/print.jl b/test/print.jl index 2a9bff0fbf9..560bb335a81 100644 --- a/test/print.jl +++ b/test/print.jl @@ -202,6 +202,15 @@ end end end +""" + printing_test(ModelType::Type{<:JuMP.AbstractModel}, + moi_backend::Bool) + +Test printing of models of type `ModelType`. The expected model printing depends +on `moi_backend` which indicates whether the model is stored in an MOI backend +or is stored in its JuMP form (i.e. as `AbstractVariable`s, +`AbstractConstraint`s and `AbstractJuMPScalar` for the objective function). +""" function printing_test(ModelType::Type{<:JuMP.AbstractModel}, moi_backend::Bool) @testset "VariableRef" begin From 35a0a22eeb39acb73dd73c158a29642c8b3f6df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 3 Jan 2019 14:49:08 +0100 Subject: [PATCH 04/11] =?UTF-8?q?=F0=9F=91=8C=20isa=20Nothing=20->=20=3D?= =?UTF-8?q?=3D=3D=20nothing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nlp.jl | 2 +- src/print.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nlp.jl b/src/nlp.jl index b5bce466c89..1a9154517e0 100644 --- a/src/nlp.jl +++ b/src/nlp.jl @@ -78,7 +78,7 @@ Returns the nonlinear objective function or `nothing` if no nonlinear objective function is set. """ function nlp_objective_function(model::Model) - if model.nlp_data isa Nothing + if model.nlp_data === nothing return nothing else return model.nlp_data.nlobj diff --git a/src/print.jl b/src/print.jl index 49095b4b860..06cfbe30539 100644 --- a/src/print.jl +++ b/src/print.jl @@ -164,7 +164,7 @@ function Base.show(io::IO, model::AbstractModel) num_variables(model)) if sense != MOI.FEASIBILITY_SENSE nlobj = nlp_objective_function(model) - if nlobj isa Nothing + if nlobj === nothing println(io, "Objective function type: ", objective_function_type(model)) else From f7acdabc05604605870151377b668861a3af4e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 3 Jan 2019 14:57:03 +0100 Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=93=9D=20Document=20constraints=20s?= =?UTF-8?q?how=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/print.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/print.jl b/src/print.jl index 06cfbe30539..c3716fada14 100644 --- a/src/print.jl +++ b/src/print.jl @@ -354,6 +354,11 @@ end ## Constraints #------------------------------------------------------------------------ +""" + show_constraints_summary(io::IO, model::Model) + +Write to `io` a summary of the number of constraints. +""" function show_constraints_summary(io::IO, model::Model) for (F, S) in MOI.get(model, MOI.ListOfConstraints()) num_constraints = MOI.get(model, MOI.NumberOfConstraints{F, S}()) @@ -366,6 +371,12 @@ function show_constraints_summary(io::IO, model::Model) end end +""" + constraints_string(print_mode, model::Model, sep, eol)::String + +Return a `String` containing the constraints of the model, each on a line +starting with `sep` and ending with `eol` (which already contains `\n`). +""" function constraints_string(print_mode, model::Model, sep, eol) str = "" for (F, S) in MOI.get(model, MOI.ListOfConstraints()) From 90344be561a0406b38730704f360324af9b5992c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 3 Jan 2019 14:58:40 +0100 Subject: [PATCH 06/11] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20isa=20Nothing=20->?= =?UTF-8?q?=20=3D=3D=3D=20nothing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/print.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/print.jl b/src/print.jl index c3716fada14..5dea1de5764 100644 --- a/src/print.jl +++ b/src/print.jl @@ -217,7 +217,7 @@ function model_string(print_mode, model::AbstractModel) end str *= sep nlobj = nlp_objective_function(model) - if nlobj isa Nothing + if nlobj === nothing str *= function_string(print_mode, objective_function(model)) else str *= nl_expr_string(model, print_mode, nlobj) From 81830a66716ca3c241788c35c6947af90874f2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 3 Jan 2019 16:05:13 +0100 Subject: [PATCH 07/11] Add objective show functions --- src/print.jl | 33 ++++++++++++++++++++------------- test/JuMPExtension.jl | 10 ++++++++-- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/print.jl b/src/print.jl index 5dea1de5764..b277edfc301 100644 --- a/src/print.jl +++ b/src/print.jl @@ -163,13 +163,7 @@ function Base.show(io::IO, model::AbstractModel) println(io, "Variable", plural(num_variables(model)), ": ", num_variables(model)) if sense != MOI.FEASIBILITY_SENSE - nlobj = nlp_objective_function(model) - if nlobj === nothing - println(io, "Objective function type: ", - objective_function_type(model)) - else - println(io, "Objective function type: Nonlinear") - end + show_objective_function_summary(io, model) end show_constraints_summary(io, model) show_backend_summary(io, model) @@ -216,12 +210,7 @@ function model_string(print_mode, model::AbstractModel) str *= "\\quad" end str *= sep - nlobj = nlp_objective_function(model) - if nlobj === nothing - str *= function_string(print_mode, objective_function(model)) - else - str *= nl_expr_string(model, print_mode, nlobj) - end + str *= objective_function_string(print_mode, model) end str *= eol str *= ijl ? "\\text{Subject to} \\quad" : "Subject to" * eol @@ -232,6 +221,24 @@ function model_string(print_mode, model::AbstractModel) return str end +function show_objective_function_summary(io::IO, model::Model) + nlobj = nlp_objective_function(model) + print(io, "Objective function type: ") + if nlobj === nothing + println(io, objective_function_type(model)) + else + println(io, "Nonlinear") + end +end +function objective_function_string(print_mode, model::Model) + nlobj = nlp_objective_function(model) + if nlobj === nothing + return function_string(print_mode, objective_function(model)) + else + return nl_expr_string(model, print_mode, nlobj) + end +end + #------------------------------------------------------------------------ ## VariableRef #------------------------------------------------------------------------ diff --git a/test/JuMPExtension.jl b/test/JuMPExtension.jl index f19cd62207d..d041f77f9a4 100644 --- a/test/JuMPExtension.jl +++ b/test/JuMPExtension.jl @@ -219,7 +219,6 @@ function JuMP.constraint_object(cref::MyConstraintRef) end # Objective -JuMP.nlp_objective_function(::MyModel) = nothing function JuMP.set_objective(m::MyModel, sense::MOI.OptimizationSense, f::JuMP.AbstractJuMPScalar) m.objectivesense = sense @@ -301,11 +300,18 @@ function JuMP.constraint_by_name(model::MyModel, name::String) end # Show +function JuMP.show_backend_summary(io::IO, model::MyModel) end +function JuMP.show_objective_function_summary(io::IO, model::MyModel) + println(io, "Objective function type: ", + JuMP.objective_function_type(model)) +end +function JuMP.objective_function_string(print_mode, model::MyModel) + return JuMP.function_string(print_mode, JuMP.objective_function(model)) +end function JuMP.show_constraints_summary(io::IO, model::MyModel) n = length(model.constraints) print(io, "Constraint", JuMP.plural(n), ": ", n) end -function JuMP.show_backend_summary(io::IO, model::MyModel) end function JuMP.constraints_string(print_mode, model::MyModel, sep, eol) str = "" # Sort by creation order, i.e. ConstraintIndex value From 3578537e46f35f2738816fdeefcbd883b66a523b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 3 Jan 2019 16:07:55 +0100 Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/print.jl | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/print.jl b/src/print.jl index b277edfc301..1fc464db45a 100644 --- a/src/print.jl +++ b/src/print.jl @@ -221,6 +221,11 @@ function model_string(print_mode, model::AbstractModel) return str end +""" + show_objective_function_summary(io::IO, model::AbstractModel) + +Write to `io` a summary of the objective function type. +""" function show_objective_function_summary(io::IO, model::Model) nlobj = nlp_objective_function(model) print(io, "Objective function type: ") @@ -230,6 +235,12 @@ function show_objective_function_summary(io::IO, model::Model) println(io, "Nonlinear") end end + +""" + objective_function_string(print_mode, model::AbstractModel)::String + +Return a `String` describing the objective function of the model. +""" function objective_function_string(print_mode, model::Model) nlobj = nlp_objective_function(model) if nlobj === nothing @@ -362,7 +373,7 @@ end #------------------------------------------------------------------------ """ - show_constraints_summary(io::IO, model::Model) + show_constraints_summary(io::IO, model::AbstractModel) Write to `io` a summary of the number of constraints. """ @@ -379,9 +390,9 @@ function show_constraints_summary(io::IO, model::Model) end """ - constraints_string(print_mode, model::Model, sep, eol)::String + constraints_string(print_mode, model::AbstractModel, sep, eol)::String -Return a `String` containing the constraints of the model, each on a line +Return a `String` describing the constraints of the model, each on a line starting with `sep` and ending with `eol` (which already contains `\n`). """ function constraints_string(print_mode, model::Model, sep, eol) From c0dfb4c5d411d661c29a90b2f51023ec97444e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 3 Jan 2019 16:10:39 +0100 Subject: [PATCH 09/11] =?UTF-8?q?=F0=9F=93=9D=20Add=20comments=20on=20what?= =?UTF-8?q?=20an=20AbstactModel=20should=20do?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/print.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/print.jl b/src/print.jl index 1fc464db45a..8571cd461a0 100644 --- a/src/print.jl +++ b/src/print.jl @@ -148,6 +148,9 @@ plural(n) = (n==1 ? "" : "s") #------------------------------------------------------------------------ ## Model #------------------------------------------------------------------------ + +# An `AbstractModel` subtype should implement `show_objective_function_summary`, +# `show_constraints_summary` and `show_backend_summary` for this method to work. function Base.show(io::IO, model::AbstractModel) println(io, "A JuMP Model") sense = objective_sense(model) @@ -192,6 +195,9 @@ end function Base.show(io::IO, ::MIME"text/latex", model::AbstractModel) print(io, wrap_in_math_mode(model_string(IJuliaMode, model))) end + +# An `AbstractModel` subtype should implement `objective_function_string` and +# `constraints_string` for this method to work. function model_string(print_mode, model::AbstractModel) ijl = print_mode == IJuliaMode sep = ijl ? " & " : " " From ff3e01a4c5afd83549d08b1376c60991497733fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 4 Jan 2019 14:41:54 +0100 Subject: [PATCH 10/11] =?UTF-8?q?=E2=9C=85=20Split=20model=5Fprinting=20in?= =?UTF-8?q?=20two=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/print.jl | 333 +++++++++++++++++++++++++++----------------------- 1 file changed, 182 insertions(+), 151 deletions(-) diff --git a/test/print.jl b/test/print.jl index 560bb335a81..666bb0b4882 100644 --- a/test/print.jl +++ b/test/print.jl @@ -202,17 +202,7 @@ end end end -""" - printing_test(ModelType::Type{<:JuMP.AbstractModel}, - moi_backend::Bool) - -Test printing of models of type `ModelType`. The expected model printing depends -on `moi_backend` which indicates whether the model is stored in an MOI backend -or is stored in its JuMP form (i.e. as `AbstractVariable`s, -`AbstractConstraint`s and `AbstractJuMPScalar` for the objective function). -""" -function printing_test(ModelType::Type{<:JuMP.AbstractModel}, - moi_backend::Bool) +function printing_test(ModelType::Type{<:JuMP.AbstractModel}) @testset "VariableRef" begin m = ModelType() @variable(m, 0 <= x <= 2) @@ -346,6 +336,11 @@ function printing_test(ModelType::Type{<:JuMP.AbstractModel}, io_test(REPLMode, quad_constr, "2 x$sq $le 1.0") # TODO: Test in IJulia mode. end +end + +# Test printing of models of type `ModelType` for which the model is stored in +# an MOI backend +function model_printing_test(ModelType::Type{<:JuMP.AbstractModel}) @testset "Model" begin repl(s) = JuMP.math_symbol(REPLMode, s) le, ge, eq, fa = repl(:leq), repl(:geq), repl(:eq), repl(:for_all) @@ -375,105 +370,165 @@ function printing_test(ModelType::Type{<:JuMP.AbstractModel}, VariableType = typeof(a) - if moi_backend - io_test(REPLMode, model_1, """ - Max a - b + 2 a1 - 10 x - Subject to - x binary - u[1] binary - u[2] binary - u[3] binary - a1 integer - b1 integer - c1 integer - z integer - fi $eq 9.0 - a $ge 1.0 - c $ge -1.0 - a1 $ge 1.0 - c1 $ge -1.0 - b $le 1.0 - c $le 1.0 - b1 $le 1.0 - c1 $le 1.0 - a + b - 10 c - 2 x + c1 $le 1.0 - a*b $le 2.0 - [-a + 1, u[1], u[2], u[3]] $inset MathOptInterface.SecondOrderCone(4) - """, repl=:print) - else - # TODO variable constraints - io_test(REPLMode, model_1, """ - Max a - b + 2 a1 - 10 x - Subject to - a + b - 10 c - 2 x + c1 $le 1.0 - a*b $le 2.0 - [-a + 1, u[1], u[2], u[3]] $inset MathOptInterface.SecondOrderCone(4) - """, repl=:print) - end + io_test(REPLMode, model_1, """ + Max a - b + 2 a1 - 10 x + Subject to + x binary + u[1] binary + u[2] binary + u[3] binary + a1 integer + b1 integer + c1 integer + z integer + fi $eq 9.0 + a $ge 1.0 + c $ge -1.0 + a1 $ge 1.0 + c1 $ge -1.0 + b $le 1.0 + c $le 1.0 + b1 $le 1.0 + c1 $le 1.0 + a + b - 10 c - 2 x + c1 $le 1.0 + a*b $le 2.0 + [-a + 1, u[1], u[2], u[3]] $inset MathOptInterface.SecondOrderCone(4) + """, repl=:print) + + io_test(REPLMode, model_1, """ + A JuMP Model + Maximization problem with: + Variables: 13 + Objective function type: JuMP.GenericAffExpr{Float64,$VariableType} + `MathOptInterface.SingleVariable`-in-`MathOptInterface.ZeroOne`: 4 constraints + `MathOptInterface.SingleVariable`-in-`MathOptInterface.Integer`: 4 constraints + `MathOptInterface.SingleVariable`-in-`MathOptInterface.EqualTo{Float64}`: 1 constraint + `MathOptInterface.SingleVariable`-in-`MathOptInterface.GreaterThan{Float64}`: 4 constraints + `MathOptInterface.SingleVariable`-in-`MathOptInterface.LessThan{Float64}`: 4 constraints + `MathOptInterface.ScalarAffineFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint + `MathOptInterface.ScalarQuadraticFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint + `MathOptInterface.VectorAffineFunction{Float64}`-in-`MathOptInterface.SecondOrderCone`: 1 constraint + Model mode: AUTOMATIC + CachingOptimizer state: NO_OPTIMIZER + Solver name: No optimizer attached. + Names registered in the model: a, a1, b, b1, c, c1, fi, u, x, y, z""", repl=:show) + + io_test(IJuliaMode, model_1, """ + \\begin{alignat*}{1}\\max\\quad & a - b + 2 a1 - 10 x\\\\ + \\text{Subject to} \\quad & x binary\\\\ + & u_{1} binary\\\\ + & u_{2} binary\\\\ + & u_{3} binary\\\\ + & a1 integer\\\\ + & b1 integer\\\\ + & c1 integer\\\\ + & z integer\\\\ + & fi = 9.0\\\\ + & a \\geq 1.0\\\\ + & c \\geq -1.0\\\\ + & a1 \\geq 1.0\\\\ + & c1 \\geq -1.0\\\\ + & b \\leq 1.0\\\\ + & c \\leq 1.0\\\\ + & b1 \\leq 1.0\\\\ + & c1 \\leq 1.0\\\\ + & a + b - 10 c - 2 x + c1 \\leq 1.0\\\\ + & a\\times b \\leq 2.0\\\\ + & [-a + 1, u_{1}, u_{2}, u_{3}] \\in MathOptInterface.SecondOrderCone(4)\\\\ + \\end{alignat*} + """) + #------------------------------------------------------------------ - if moi_backend - io_test(REPLMode, model_1, """ - A JuMP Model - Maximization problem with: - Variables: 13 - Objective function type: JuMP.GenericAffExpr{Float64,$VariableType} - `MathOptInterface.SingleVariable`-in-`MathOptInterface.ZeroOne`: 4 constraints - `MathOptInterface.SingleVariable`-in-`MathOptInterface.Integer`: 4 constraints - `MathOptInterface.SingleVariable`-in-`MathOptInterface.EqualTo{Float64}`: 1 constraint - `MathOptInterface.SingleVariable`-in-`MathOptInterface.GreaterThan{Float64}`: 4 constraints - `MathOptInterface.SingleVariable`-in-`MathOptInterface.LessThan{Float64}`: 4 constraints - `MathOptInterface.ScalarAffineFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint - `MathOptInterface.ScalarQuadraticFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint - `MathOptInterface.VectorAffineFunction{Float64}`-in-`MathOptInterface.SecondOrderCone`: 1 constraint - Model mode: AUTOMATIC - CachingOptimizer state: NO_OPTIMIZER - Solver name: No optimizer attached. - Names registered in the model: a, a1, b, b1, c, c1, fi, u, x, y, z""", repl=:show) - else - io_test(REPLMode, model_1, """ - A JuMP Model - Maximization problem with: - Variables: 13 - Objective function type: JuMP.GenericAffExpr{Float64,$VariableType} - Constraints: 3 - Names registered in the model: a, a1, b, b1, c, c1, fi, u, x, y, z""", repl=:show) - end + model_2 = ModelType() + @variable(model_2, x, Bin) + @variable(model_2, y, Int) + @constraint(model_2, x*y <= 1) - if moi_backend - io_test(IJuliaMode, model_1, """ - \\begin{alignat*}{1}\\max\\quad & a - b + 2 a1 - 10 x\\\\ - \\text{Subject to} \\quad & x binary\\\\ - & u_{1} binary\\\\ - & u_{2} binary\\\\ - & u_{3} binary\\\\ - & a1 integer\\\\ - & b1 integer\\\\ - & c1 integer\\\\ - & z integer\\\\ - & fi = 9.0\\\\ - & a \\geq 1.0\\\\ - & c \\geq -1.0\\\\ - & a1 \\geq 1.0\\\\ - & c1 \\geq -1.0\\\\ - & b \\leq 1.0\\\\ - & c \\leq 1.0\\\\ - & b1 \\leq 1.0\\\\ - & c1 \\leq 1.0\\\\ - & a + b - 10 c - 2 x + c1 \\leq 1.0\\\\ - & a\\times b \\leq 2.0\\\\ - & [-a + 1, u_{1}, u_{2}, u_{3}] \\in MathOptInterface.SecondOrderCone(4)\\\\ - \\end{alignat*} - """) - else - io_test(IJuliaMode, model_1, """ - \\begin{alignat*}{1}\\max\\quad & a - b + 2 a1 - 10 x\\\\ - \\text{Subject to} \\quad & a + b - 10 c - 2 x + c1 \\leq 1.0\\\\ - & a\\times b \\leq 2.0\\\\ - & [-a + 1, u_{1}, u_{2}, u_{3}] \\in MathOptInterface.SecondOrderCone(4)\\\\ - \\end{alignat*} - """) - end + io_test(REPLMode, model_2, """ + A JuMP Model + Feasibility problem with: + Variables: 2 + `MathOptInterface.SingleVariable`-in-`MathOptInterface.ZeroOne`: 1 constraint + `MathOptInterface.SingleVariable`-in-`MathOptInterface.Integer`: 1 constraint + `MathOptInterface.ScalarQuadraticFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint + Model mode: AUTOMATIC + CachingOptimizer state: NO_OPTIMIZER + Solver name: No optimizer attached. + Names registered in the model: x, y""", repl=:show) + + model_3 = ModelType() + @variable(model_3, x) + @constraint(model_3, x <= 3) + + io_test(REPLMode, model_3, """ + A JuMP Model + Feasibility problem with: + Variable: 1 + `MathOptInterface.ScalarAffineFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint + Model mode: AUTOMATIC + CachingOptimizer state: NO_OPTIMIZER + Solver name: No optimizer attached. + Names registered in the model: x""", repl=:show) + end +end + +# Test printing of models of type `ModelType` for which the model is stored in +# its JuMP form, e.g., as `AbstractVariable`s and `AbstractConstraint`s. +function model_extension_printing_test(ModelType::Type{<:JuMP.AbstractModel}) + @testset "Model" begin + repl(s) = JuMP.math_symbol(REPLMode, s) + le, ge, eq, fa = repl(:leq), repl(:geq), repl(:eq), repl(:for_all) + inset, dots = repl(:in), repl(:dots) + infty, union = repl(:infty), repl(:union) + Vert, sub2 = repl(:Vert), repl(:sub2) + for_all = repl(:for_all) + + #------------------------------------------------------------------ + + model_1 = ModelType() + @variable(model_1, a>=1) + @variable(model_1, b<=1) + @variable(model_1, -1<=c<=1) + @variable(model_1, a1>=1,Int) + @variable(model_1, b1<=1,Int) + @variable(model_1, -1<=c1<=1,Int) + @variable(model_1, x, Bin) + @variable(model_1, y) + @variable(model_1, z, Int) + @variable(model_1, u[1:3], Bin) + @variable(model_1, fi == 9) + @objective(model_1, Max, a - b + 2a1 - 10x) + @constraint(model_1, a + b - 10c - 2x + c1 <= 1) + @constraint(model_1, a*b <= 2) + @constraint(model_1, [1 - a; u] in SecondOrderCone()) + + VariableType = typeof(a) + + # TODO variable constraints + io_test(REPLMode, model_1, """ + Max a - b + 2 a1 - 10 x + Subject to + a + b - 10 c - 2 x + c1 $le 1.0 + a*b $le 2.0 + [-a + 1, u[1], u[2], u[3]] $inset MathOptInterface.SecondOrderCone(4) + """, repl=:print) + + io_test(REPLMode, model_1, """ + A JuMP Model + Maximization problem with: + Variables: 13 + Objective function type: JuMP.GenericAffExpr{Float64,$VariableType} + Constraints: 3 + Names registered in the model: a, a1, b, b1, c, c1, fi, u, x, y, z""", repl=:show) + + io_test(IJuliaMode, model_1, """ + \\begin{alignat*}{1}\\max\\quad & a - b + 2 a1 - 10 x\\\\ + \\text{Subject to} \\quad & a + b - 10 c - 2 x + c1 \\leq 1.0\\\\ + & a\\times b \\leq 2.0\\\\ + & [-a + 1, u_{1}, u_{2}, u_{3}] \\in MathOptInterface.SecondOrderCone(4)\\\\ + \\end{alignat*} + """) #------------------------------------------------------------------ @@ -482,54 +537,29 @@ function printing_test(ModelType::Type{<:JuMP.AbstractModel}, @variable(model_2, y, Int) @constraint(model_2, x*y <= 1) - if moi_backend - io_test(REPLMode, model_2, """ - A JuMP Model - Feasibility problem with: - Variables: 2 - `MathOptInterface.SingleVariable`-in-`MathOptInterface.ZeroOne`: 1 constraint - `MathOptInterface.SingleVariable`-in-`MathOptInterface.Integer`: 1 constraint - `MathOptInterface.ScalarQuadraticFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint - Model mode: AUTOMATIC - CachingOptimizer state: NO_OPTIMIZER - Solver name: No optimizer attached. - Names registered in the model: x, y""", repl=:show) - else - io_test(REPLMode, model_2, """ - A JuMP Model - Feasibility problem with: - Variables: 2 - Constraint: 1 - Names registered in the model: x, y""", repl=:show) - end + io_test(REPLMode, model_2, """ + A JuMP Model + Feasibility problem with: + Variables: 2 + Constraint: 1 + Names registered in the model: x, y""", repl=:show) - model_2 = ModelType() - @variable(model_2, x) - @constraint(model_2, x <= 3) - - if moi_backend - io_test(REPLMode, model_2, """ - A JuMP Model - Feasibility problem with: - Variable: 1 - `MathOptInterface.ScalarAffineFunction{Float64}`-in-`MathOptInterface.LessThan{Float64}`: 1 constraint - Model mode: AUTOMATIC - CachingOptimizer state: NO_OPTIMIZER - Solver name: No optimizer attached. - Names registered in the model: x""", repl=:show) - else - io_test(REPLMode, model_2, """ - A JuMP Model - Feasibility problem with: - Variable: 1 - Constraint: 1 - Names registered in the model: x""", repl=:show) - end + model_3 = ModelType() + @variable(model_3, x) + @constraint(model_3, x <= 3) + + io_test(REPLMode, model_3, """ + A JuMP Model + Feasibility problem with: + Variable: 1 + Constraint: 1 + Names registered in the model: x""", repl=:show) end end @testset "Printing for JuMP.Model" begin - printing_test(Model, true) + printing_test(Model) + model_printing_test(Model) @testset "Model with nonlinear terms" begin eq = JuMP.math_symbol(REPLMode, :eq) model = Model() @@ -574,5 +604,6 @@ end end @testset "Printing for JuMPExtension.MyModel" begin - printing_test(JuMPExtension.MyModel, false) + printing_test(JuMPExtension.MyModel) + model_extension_printing_test(JuMPExtension.MyModel) end From c8d6ef4f5b98dda973e6bd813db504171ffc2abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 5 Jan 2019 22:33:05 +0100 Subject: [PATCH 11/11] Add comment explaining design --- test/print.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/print.jl b/test/print.jl index 666bb0b4882..c48d033802e 100644 --- a/test/print.jl +++ b/test/print.jl @@ -475,6 +475,8 @@ end # Test printing of models of type `ModelType` for which the model is stored in # its JuMP form, e.g., as `AbstractVariable`s and `AbstractConstraint`s. +# This is used by `JuMPExtension` but can also be used by external packages such +# as `StructJuMP`, see https://github.com/JuliaOpt/JuMP.jl/issues/1711 function model_extension_printing_test(ModelType::Type{<:JuMP.AbstractModel}) @testset "Model" begin repl(s) = JuMP.math_symbol(REPLMode, s)