I’m implementing a formula engine in JuMP where users can define expressions like:
z = min(x, y)
and I translate these automatically into JuMP constraints.
I have tried two formulations:
1. SOS1 formulation
function minOf2(model, vars...)
z = @variable(model)
δ = @variable(model, [1:length(vars)])
@constraint(model, δ .>= 0)
for (i, v) in enumerate(vars)
@constraint(model, z <= v)
@constraint(model, z + δ[i] == v)
end
@constraint(model, δ in SOS1())
return z
end
This works for small models, but once the number of min() expressions increases (and therefore SOS1 sets grow), SCIP fails to converge or stalls extremely early.
2. Big-M formulation
I also tried the classic binary + Big-M:
z ≤ v[i]
z ≥ v[i] - M * (1 - b[i])
This works only when M is tight.
In my application, user-provided values don’t always have good bounds, and large M values quickly introduce numerical instability in SCIP.
My question
Given that:
- SOS1 scaling is poor in SCIP for many min/max operators
- Big-M is unstable when
Mis not tight - I cannot reliably compute tight bounds because user formulas are arbitrary
What is the recommended way in JuMP/SCIP to model min() reliably in large models?
Are there alternative formulations that scale better?
Any practical advice for building a formula engine on top of JuMP would be greatly appreciated.