# JuliaOpt/JuMP.jl

```* Add drop_zeros function

* Fix tests

* drop_zeros -> drop_zeros!```
odow committed Apr 9, 2019
1 parent 2f16407 commit 8809ab71858356d5685e9c9c7e39517ae2d1ceb6
Showing with 106 additions and 15 deletions.
1. +43 −2 docs/src/expressions.md
2. +14 −0 src/aff_expr.jl
3. +1 −5 src/print.jl
5. +18 −0 test/expr.jl
6. +4 −5 test/operator.jl
7. +11 −3 test/print.jl
 @@ -112,6 +112,26 @@ add_to_expression!(ex, 1.0, y) 2 x + y - 1 ``` ### Removing zero terms Use [`drop_zeros!`](@ref) to remove terms from an affine expression with a `0` coefficient. ```jldoctest julia> model = Model(); julia> @variable(model, x) x julia> @expression(model, ex, 0 * x + 1) 0 x + 1 julia> drop_zeros!(ex) julia> ex 1 ``` ## Quadratic expressions Like affine expressions, there are four ways of constructing a quadratic @@ -188,17 +208,38 @@ add_to_expression!(ex, 1.0, y, y) x² + 2 x*y + y² + x + y - 1 ``` ### Removing zero terms Use [`drop_zeros!`](@ref) to remove terms from a quadratic expression with a `0` coefficient. ```jldoctest julia> model = Model(); julia> @variable(model, x) x julia> @expression(model, ex, 0 * x^2 + x + 1) 0 x² + x + 1 julia> drop_zeros!(ex) julia> ex x + 1 ``` ## Nonlinear expressions Nonlinear expressions can be constructed only using the [`@NLexpression`](@ref) macro and can be used only in [`@NLobjective`](@ref), [`@NLconstraint`](@ref), and other [`@NLexpression`](@ref)s. Moreover, quadratic and affine expressions cannot be used in the nonlinear macros. For more details, see the [Nonlinear Modeling](@ref) section. Modeling](@ref) section. ## Reference ```@docs @expression JuMP.add_to_expression! add_to_expression! drop_zeros! ```
 @@ -92,6 +92,20 @@ Base.one( a::GenericAffExpr) = one(typeof(a)) Base.copy(a::GenericAffExpr) = GenericAffExpr(copy(a.constant), copy(a.terms)) Base.broadcastable(a::GenericAffExpr) = Ref(a) """ drop_zeros!(expr::GenericAffExpr) Remove terms in the affine expression with `0` coefficients. """ function drop_zeros!(expr::GenericAffExpr) for (key, coef) in expr.terms if iszero(coef) delete!(expr.terms, key) end end return end GenericAffExpr{C, V}() where {C, V} = zero(GenericAffExpr{C, V}) function map_coefficients_inplace!(f::Function, a::GenericAffExpr)
 @@ -300,10 +300,8 @@ function function_string(mode, a::GenericAffExpr, show_constant=true) term_str = Array{String}(undef, 2 * length(linear_terms(a))) elm = 1 # For each non-zero for this model for (coef, var) in linear_terms(a) _is_zero_for_printing(coef) && continue # e.g. x - x for (coef, var) in linear_terms(a) pre = _is_one_for_printing(coef) ? "" : _string_round(abs(coef)) * " " term_str[2 * elm - 1] = _sign_string(coef) @@ -339,8 +337,6 @@ function function_string(mode, q::GenericQuadExpr) elm = 1 if length(term_str) > 0 for (coef, var1, var2) in quad_terms(q) _is_zero_for_printing(coef) && continue # e.g. x - x pre = _is_one_for_printing(coef) ? "" : _string_round(abs(coef)) * " " x = function_string(mode, var1)
 @@ -63,6 +63,21 @@ Base.one(q::GenericQuadExpr) = one(typeof(q)) Base.copy(q::GenericQuadExpr) = GenericQuadExpr(copy(q.aff), copy(q.terms)) Base.broadcastable(q::GenericQuadExpr) = Ref(q) """ drop_zeros!(expr::GenericQuadExpr) Remove terms in the quadratic expression with `0` coefficients. """ function drop_zeros!(expr::GenericQuadExpr) drop_zeros!(expr.aff) for (key, coef) in expr.terms if iszero(coef) delete!(expr.terms, key) end end return end function map_coefficients_inplace!(f::Function, q::GenericQuadExpr) # The iterator remains valid if existing elements are updated. for (key, value) in q.terms
 @@ -22,6 +22,15 @@ function expressions_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @test hash(x + 1) == hash(x + 1) end @testset "drop_zeros!(::GenericAffExpr)" begin m = ModelType() @variable(m, x[1:2]) expr = x[1] + 0.0 * x[2] + 1 @test !isequal(expr, x[1] + 1) JuMP.drop_zeros!(expr) @test isequal(expr, x[1] + 1) end @testset "iszero(::GenericAffExpr)" begin m = ModelType() @variable(m, x) @@ -43,6 +52,15 @@ function expressions_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @test hash(x^2 + 1) == hash(x^2 + 1) end @testset "drop_zeros!(::GenericQuadExpr)" begin m = ModelType() @variable(m, x[1:2]) expr = x[1]^2 + 0.0 * x[2]^2 + x[1] + 0.0 * x[2] + 1 @test !isequal(expr, x[1]^2 + x[1] + 1) JuMP.drop_zeros!(expr) @test isequal(expr, x[1]^2 + x[1] + 1) end @testset "iszero(::GenericQuadExpr)" begin m = ModelType() @variable(m, x)
 @@ -142,17 +142,16 @@ function operators_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType:: @test_expression_with_string w + x "w + x" @test_expression_with_string w - x "w - x" @test_expression_with_string w * x "w*x" @test_expression_with_string x - x "0" @test_expression_with_string x - x "0 x" @test_throws ErrorException w / x @test_expression_with_string y*z - x "y*z - x" @test_expression_with_string x - x "0" # 2-3 Variable--AffExpr @test_expression_with_string z + aff "z + 7.1 x + 2.5" @test_expression_with_string z - aff "z - 7.1 x - 2.5" @test_expression_with_string z * aff "7.1 z*x + 2.5 z" @test_throws ErrorException z / aff @test_throws MethodError z ≤ aff @test_expression_with_string 7.1 * x - aff "-2.5" @test_expression_with_string 7.1 * x - aff "0 x - 2.5" # 2-4 Variable--QuadExpr @test_expression_with_string w + q "2.5 y*z + w + 7.1 x + 2.5" @test_expression_with_string w - q "-2.5 y*z + w - 7.1 x - 2.5" @@ -189,14 +188,14 @@ function operators_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType:: @test_expression_with_string aff - z "7.1 x - z + 2.5" @test_expression_with_string aff * z "7.1 x*z + 2.5 z" @test_throws ErrorException aff/z @test_expression_with_string aff - 7.1 * x "2.5" @test_expression_with_string aff - 7.1 * x "0 x + 2.5" # 3-3 AffExpr--AffExpr @test_expression_with_string aff + aff2 "7.1 x + 1.2 y + 3.7" @test_expression_with_string aff - aff2 "7.1 x - 1.2 y + 1.3" @test_expression_with_string aff * aff2 "8.52 x*y + 3 y + 8.52 x + 3" @test string((x+x)*(x+3)) == string((x+3)*(x+x)) # Issue #288 @test_throws ErrorException aff/aff2 @test_expression_with_string aff-aff "0" @test_expression_with_string aff-aff "0 x" # 4-4 AffExpr--QuadExpr @test_expression_with_string aff2 + q "2.5 y*z + 1.2 y + 7.1 x + 3.7" @test_expression_with_string aff2 - q "-2.5 y*z + 1.2 y - 7.1 x - 1.3"
 @@ -10,7 +10,7 @@ # test/print.jl # Testing \$fa pretty-printing-related functionality ############################################################################# using MathOptInterface using JuMP using LinearAlgebra, Test import JuMP.REPLMode, JuMP.IJuliaMode @@ -116,6 +116,11 @@ end ex = @expression(mod, -z*x[1] - x[1]*z + x[1]*x[2] + 0*z^2) io_test(REPLMode, ex, "-2 x[1]*z + x[1]*x[2]") io_test(IJuliaMode, ex, "-2 x_{1}\\times z + x_{1}\\times x_{2}") ex = 0 * z^2 + 0 * x[1] io_test(REPLMode, ex, "0 z² + 0 x[1]") io_test(IJuliaMode, ex, "0 z\$ijulia_sq + 0 x_{1}") end # See https://github.com/JuliaOpt/JuMP.jl/pull/1352 @@ -125,6 +130,9 @@ end @variable m y u = UnitNumber(2.0) aff = JuMP.GenericAffExpr(zero(u), x => u, y => zero(u)) io_test(REPLMode, aff, "UnitNumber(2.0) x + UnitNumber(0.0) y") io_test(IJuliaMode, aff, "UnitNumber(2.0) x + UnitNumber(0.0) y") drop_zeros!(aff) io_test(REPLMode, aff, "UnitNumber(2.0) x") io_test(IJuliaMode, aff, "UnitNumber(2.0) x") quad = aff * x @@ -272,7 +280,7 @@ function printing_test(ModelType::Type{<:JuMP.AbstractModel}) model = ModelType() @variable(model, x) @variable(model, y) zero_constr = @constraint(model, [x, y] in MathOptInterface.Zeros(2)) zero_constr = @constraint(model, [x, y] in MOI.Zeros(2)) io_test(REPLMode, zero_constr, "[x, y] \$in_sym MathOptInterface.Zeros(2)") @@ -619,7 +627,7 @@ end in_sym = JuMP._math_symbol(REPLMode, :in) model = Model() @variable(model, x >= 10) zero_one = @constraint(model, x in MathOptInterface.ZeroOne()) zero_one = @constraint(model, x in MOI.ZeroOne()) io_test(REPLMode, JuMP.LowerBoundRef(x), "x \$ge 10.0") io_test(REPLMode, zero_one, "x binary")