SumOfSquares.jl icon indicating copy to clipboard operation
SumOfSquares.jl copied to clipboard

Non-commutative optimization under constraints fails

Open araujoms opened this issue 2 years ago • 2 comments

The following code gives me a stack overflow error:

using DynamicPolynomials
using SumOfSquares
import SCS

model = Model(SCS.Optimizer)

@ncpolyvar a0 a1 b0 b1
p = a0*b0 + a0*b1 + a1*b0 - a1*b1
@variable(model, λ)
@objective(model, Min, λ)
S = @set a0^2 == 1 && a1^2 == 1 && b0^2 == 1 && b1^2 == 1
con_ref = @constraint(model, λ - p in SOSCone(), domain = S)

optimize!(model)

Here I'm optimizing the CHSH functional, the simplest problem in nonlocality. The documentation is not clear whether this is supposed to work. If I change @ncpolyvar to @polyvar then it works, and the answer is 2*sqrt(2) as expected.

araujoms avatar Apr 07 '23 15:04 araujoms

A more minimal example is

julia> using DynamicPolynomials

julia> using SumOfSquares

julia> import SCS

julia> model = Model(SCS.Optimizer)
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: SCS

julia> @ncpolyvar a
(a,)

julia> @constraint(model, a in SOSCone(), domain = @set a^2 == 1)
(1)a is SOS

julia> optimize!(model)
ERROR: StackOverflowError:
Stacktrace:
 [1] mapexponents(f::Function, m1::Monomial{false}, m2::Monomial{false}) (repeats 79984 times)
   @ MultivariatePolynomials ~/.julia/packages/MultivariatePolynomials/sWAOE/src/monomial.jl:128

odow avatar Apr 10 '23 20:04 odow

Thanks for reporting this, the noncommutative part does not have enough tests unfortunately, especially with constraints

blegat avatar Apr 11 '23 05:04 blegat

I'm running into the exact same problem, and I fail to understand the logic behind map_exponents to try to fix things. In particular, it's not clear where the function targeted by map_exponents(f, monomial(m1), monomial(m2)) in monomial.jl:147 is supposed to be. For the moment, this calls itself indefinitely, hence the error. Any thoughts?

Also, I've noticed that the minimal example above is now throwing a different error as it's trying to divide polynomials with non-commutative variables. Here is the beginning of this error.

ERROR: Not implemented yet
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:35
  [2] divides(m1::DynamicPolynomials.Monomial{…}, m2::DynamicPolynomials.Monomial{…})
    @ DynamicPolynomials ~/.julia/packages/DynamicPolynomials/UsmGj/src/div.jl:2
  [3] divides(t1::DynamicPolynomials.Monomial{…}, t2::Term{…})
    @ MultivariatePolynomials ~/.julia/packages/MultivariatePolynomials/iTfZE/src/division.jl:25
  [4] divrem(f::Polynomial{…}, g::Vector{…}; kwargs::@Kwargs{})
    @ MultivariatePolynomials ~/.julia/packages/MultivariatePolynomials/iTfZE/src/division.jl:511
  [5] divrem
    @ ~/.julia/packages/MultivariatePolynomials/iTfZE/src/division.jl:485 [inlined]
  [6] #rem#115
    @ ~/.julia/packages/MultivariatePolynomials/iTfZE/src/division.jl:196 [inlined]
  [7] rem
    @ ~/.julia/packages/MultivariatePolynomials/iTfZE/src/division.jl:195 [inlined]
  [8] rem
    @ ~/.julia/packages/SemialgebraicSets/BoKut/src/ideal.jl:60 [inlined]
  [9] bridge_constraint(::Type{…}, model::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, f::MathOptInterface.VectorAffineFunction{…}, s::PolyJuMP.ZeroPolynomialSet{…})
    @ PolyJuMP.Bridges.Constraint ~/.julia/packages/PolyJuMP/aU72s/src/Bridges/Constraint/zero_polynomial_in_algebraic_set.jl:31
[...]

sebastiendesignolle avatar Nov 13 '24 15:11 sebastiendesignolle

In the commutative case, several operations can fall back to mapexponents. For instance, the product of monomials is mapexponents(+, m1, m2), the division is mapexponents(-, m1, m2), the gcd is mapexponents(min, m1, m2), etc... For the noncommutative case, you can't really fall back to mapexponents or I agree with you that it's not so clear what mapexponents actually means in that case.

I refactored MultivariatePolynomials quite a lot so that if you just define a new type of monomial, you can easily make it work with SumOfSquares. See for instance https://github.com/blegat/CondensedMatterSOS.jl/

On SumOfSquares master, we refactored things to work with arbitrary basis defining the StarAlgebras interface and I showcased an example in https://youtu.be/CGPHaHxCG2w so in the future, you won't even have to implement the MultivariatePolynomials API

So these are other options than DynamicPolynomials.@ncpolyvar.

In any case, the issue here is that we trying to take the remainder modulo the ideal (which doesn't work in the noncommutative case) instead of just instantiating multipliers which is something I'd like to fix soon. In the meantime, you can create the multipliers for the equalities of the ideal manually with @variable(model, ..., Poly(...))

blegat avatar Nov 13 '24 21:11 blegat

Thanks a lot, I'll try to use this!

sebastiendesignolle avatar Nov 15 '24 04:11 sebastiendesignolle