How to impose absolute value greater than constraint

The following gives me an error and I don’t know how to fix it. I want entries of the matrix X to be bounded by -1 and 1, and in addition I wand |X(i,j)| >= 0.01 for all i and j. What am I doing wrong?

using JuMP
model = Model( )

n = 8

@variable(model, -1.0 <= X[1:n, 1:n] <= 1.0, Symmetric)
@constraint(model, minimum(abs.(X)) .>= 0.01)


MethodError: no method matching abs(::LinearAlgebra.Symmetric{VariableRef, Matrix{VariableRef}})
Closest candidates are:
  abs(::ForwardDiff.Dual{T}) where T at ~/.julia/packages/ForwardDiff/pDtsf/src/dual.jl:238
  abs(::Signed) at /Volumes/Julia-1.7.2/Julia-1.7.app/Contents/Resources/julia/share/julia/base/int.jl:180
  abs(::Unsigned) at /Volumes/Julia-1.7.2/Julia-1.7.app/Contents/Resources/julia/share/julia/base/int.jl:179
  ...

I guess that abs isn’t supported in constraints. Maybe try replacing min(abs(X)) .>= 0.01 with something like these two constraints: X[1:n, 1:n] ≤ -0.01 and 0.01 ≤ X[1:n, 1:n].

1 Like

minimum(abs.(X))?

I need OR not AND which I don’t know how to code

1 Like

Yes that’s the correct syntax but still I get the error

MethodError: no method matching abs(::VariableRef)
Closest candidates are:
  abs(::ForwardDiff.Dual{T}) where T at ~/.julia/packages/ForwardDiff/pDtsf/src/dual.jl:238
  abs(::Signed) at /Volumes/Julia-1.7.2/Julia-1.7.app/Contents/Resources/julia/share/julia/base/int.jl:180
  abs(::Unsigned) at /Volumes/Julia-1.7.2/Julia-1.7.app/Contents/Resources/julia/share/julia/base/int.jl:179

Realize that even if you can formulate this for JuMP, it’s likely to be a pretty terrible combinatorial optimization problem — your feasible set is not only non-convex, it is actually disconnected, with an exponentially large number of disjoint sign choices. It may be pretty hard (probably NP hard) for any algorithm to solve such a problem. Are you sure you can’t formulate a different problem for your application? Why do you need the absolute-value constraint?

2 Likes

As @stevengj alludes to, you can model this using binary variables:

using JuMP

function add_abs_greater_than_constraint(x::VariableRef, abs_min::Float64)
    lb, ub = lower_bound(x), upper_bound(x)
    x_neg = @variable(model, lower_bound = 0, upper_bound = -lb)
    x_pos = @variable(model, lower_bound = 0, upper_bound = ub)
    z = @variable(model, [1:2], Bin)
    @constraints(model, begin
        x == x_pos - x_neg
        sum(z) == 1
        x_pos <= z[1]
        x_pos >= abs_min * z[1]
        x_neg <= z[2]
        x_neg >= abs_min * z[2]
    end)
    return
end

n = 8
model = Model()
@variable(model, -1.0 <= X[1:n, 1:n] <= 1.0, Symmetric)
for i in 1:n, j in i:n
    add_abs_greater_than_constraint(X[i, j], 0.01)
end

But an absolute value greater than constraint is a little unusual. What’s wrong with zero elements in X?