Nonconvex and Matrix Variables

Is there any way to deal with matrix variables with Nonconvex lib ?
I tried something like:

using Nonconvex
Nonconvex.@load Ipopt

f(x) = sqrt(x[2,2])
g(x, a, b) = (a*x[1,2] + b)^3 - x[2,1]

model = Model(f)
addvar!(model, [[0.0, 0.0],[0.0,0.0]], [[10.0, 10.0],[10.0,10.0]])
add_ineq_constraint!(model, x -> g(x, 2, 0))
add_ineq_constraint!(model, x -> g(x, -1, 1))

alg = IpoptAlg()
options = IpoptOptions(first_order = true, tol = 1e-7)
r = optimize(model, alg, [[1.0,1.0],[1.0, 1.0]], options = options)

but I got the following error:

Stacktrace:
 [1] getindex
   @ ./array.jl:862 [inlined]
 [2] g(x::Vector{Vector{Float64}}, a::Int64, b::Int64)
   @ Main ~/Nextcloud/Dauphine/OptiForm/Julia/Nonconvex/test.jl:5
 [3] (::var"#1#2")(x::Vector{Vector{Float64}})
   @ Main ~/Nextcloud/Dauphine/OptiForm/Julia/Nonconvex/test.jl:9
 [4] add_ineq_constraint!(m::Model{Vector{Any}}, f::var"#1#2", s::Float64) (repeats 2 times)
   @ NonconvexCore ~/.julia/packages/NonconvexCore/uZAVo/src/models/model.jl:160
 [5] top-level scope
   @ ~/Nextcloud/Dauphine/OptiForm/Julia/Nonconvex/test.jl:9

Just reshape them to/from vectors passing them as optimization parameters to/from Nonconvex.

Your decision variables are a vector of vectors so you need x[1][2] not x[1,2]. Nonconvex supports vectors of mostly arbitrary data structures as decision variables.

using Nonconvex
Nonconvex.@load Ipopt

f(x) = sqrt(x[2][2])
g(x, a, b) = (a*x[1][2] + b)^3 - x[2][1]

model = Model(f)
addvar!(model, [[1e-4, 1e-4],[1e-4,1e-4]], [[10.0, 10.0],[10.0,10.0]])
add_ineq_constraint!(model, x -> g(x, 2, 0))
add_ineq_constraint!(model, x -> g(x, -1, 1))

alg = IpoptAlg()
options = IpoptOptions(first_order = true, tol = 1e-7)
r = optimize(model, alg, [[1.0,1.0],[1.0, 1.0]], options = options)
1 Like

Oh, I didn’t notice this.

If @chupin actually wants a “matrix” variable, then I should remind them that Julia has actual 2d arrays — you don’t need [[0.0, 0.0],[0.0,0.0]] arrays-of-arrays as you would in Python.

1 Like

Thank you for your quick answers.
In fact, I want Matrix variables because in my more complex code, I use the very usefull ones, zeros, rand, etc., that produce matrices.
I tried to convert the toy example:

using Nonconvex
Nonconvex.@load Ipopt
f(x) = sqrt(x[2,2])
g(x, a, b) = (a*x[1,2] + b)^3 - x[2,1]

model = Model(f)
addvar!(model, [1e-4 1e-4 ;  1e-4 1e-4], [10.0 10.0 ; 10.0 10.0])
add_ineq_constraint!(model, x -> g(x, 2, 0))
add_ineq_constraint!(model, x -> g(x, -1, 1))

alg = IpoptAlg()
options = IpoptOptions(first_order = true, tol = 1e-7)
r = optimize(model, alg, [1.0 1.0 ; 1.0 1.0], options = options

but I got the error:

ERROR: LoadError: BoundsError: attempt to access 1-element Vector{Matrix{Float64}} at index [1, 2]
Stacktrace:
 [1] getindex
   @ ./array.jl:862 [inlined]
 [2] g(x::Vector{Matrix{Float64}}, a::Int64, b::Int64)
   @ Main ~/Nextcloud/Dauphine/OptiForm/Julia/Nonconvex/test.jl:18
 [3] (::var"#1#2")(x::Vector{Matrix{Float64}})
   @ Main ~/Nextcloud/Dauphine/OptiForm/Julia/Nonconvex/test.jl:22
 [4] add_ineq_constraint!(m::Model{Vector{Any}}, f::var"#1#2", s::Float64) (repeats 2 times)
   @ NonconvexCore ~/.julia/packages/NonconvexCore/uZAVo/src/models/model.jl:160
 [5] top-level scope
   @ ~/Nextcloud/Dauphine/OptiForm/Julia/Nonconvex/test.jl:22
in expression starting at /home/mc/Nextcloud/Dauphine/OptiForm/Julia/Nonconvex/test.jl:22

The decision variables x is always a vector of things. In your case, you are adding a single matrix decision variable. So to get it in the function you should use x[1].

add_ineq_constraint!(model, x -> g(x[1], 2, 0))
add_ineq_constraint!(model, x -> g(x[1], -1, 1))

Thanks, but unfortunately, the following code gives a lot of errors (beginning with Zigote)

using Nonconvex
Nonconvex.@load Ipopt

f(x) = sqrt(x[2,2])
g(x, a, b) = (a*x[1,2] + b)^3 - x[2,1]

model = Model(f)
addvar!(model, [1e-4 1e-4 ;  1e-4 1e-4], [10.0 10.0 ; 10.0 10.0])
add_ineq_constraint!(model, x -> g(x[1], 2, 0))
add_ineq_constraint!(model, x -> g(x[1], -1, 1))

alg = IpoptAlg()
options = IpoptOptions(first_order = true, tol = 1e-7)
r = optimize(model, alg, [1.0 1.0 ; 1.0 1.0], options = options)

That seems to be the best way. Thanks

were you able to find a working configuration? Would you mind posting as example?

This should work. Sorry for the late response!

using Nonconvex
Nonconvex.@load Ipopt

f(x) = sqrt(x[1][2,2])
g(x, a, b) = (a*x[1,2] + b)^3 - x[2,1]

model = Model(f)
addvar!(model, [1e-4 1e-4 ;  1e-4 1e-4], [10.0 10.0 ; 10.0 10.0])
add_ineq_constraint!(model, x -> g(x[1], 2, 0))
add_ineq_constraint!(model, x -> g(x[1], -1, 1))

alg = IpoptAlg()
options = IpoptOptions(first_order = true, tol = 1e-7)
r = optimize(model, alg, [[1.0 1.0 ; 1.0 1.0]], options = options)

The 2 changes I made were

f(x) = sqrt(x[1][2,2])

and

r = optimize(model, alg, [[1.0 1.0 ; 1.0 1.0]], options = options)